├── .github
└── workflows
│ └── codeql-analysis.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── SECURITY.md
├── pom.xml
└── sike-java
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── wultra
│ └── security
│ └── pqc
│ └── sike
│ ├── crypto
│ ├── KeyGenerator.java
│ ├── RandomGenerator.java
│ ├── Sidh.java
│ └── Sike.java
│ ├── math
│ ├── api
│ │ ├── Fp2Element.java
│ │ ├── Fp2ElementFactory.java
│ │ ├── Fp2Point.java
│ │ ├── FpElement.java
│ │ ├── Isogeny.java
│ │ └── Montgomery.java
│ ├── optimized
│ │ ├── Fp2PointProjective.java
│ │ ├── IsogenyProjective.java
│ │ ├── MontgomeryProjective.java
│ │ └── fp
│ │ │ ├── Fp2ElementFactoryOpti.java
│ │ │ ├── Fp2ElementOpti.java
│ │ │ ├── FpElementOpti.java
│ │ │ └── UnsignedLong.java
│ └── reference
│ │ ├── Fp2PointAffine.java
│ │ ├── IsogenyAffine.java
│ │ ├── MontgomeryAffine.java
│ │ └── fp
│ │ ├── Fp2ElementFactoryRef.java
│ │ ├── Fp2ElementRef.java
│ │ └── FpElementRef.java
│ ├── model
│ ├── EncapsulationResult.java
│ ├── EncryptedMessage.java
│ ├── EvaluatedCurve.java
│ ├── ImplementationType.java
│ ├── MontgomeryCurve.java
│ ├── Party.java
│ ├── SidhPrivateKey.java
│ ├── SidhPublicKey.java
│ └── optimized
│ │ └── MontgomeryConstants.java
│ ├── param
│ ├── SikeParam.java
│ ├── SikeParamP434.java
│ ├── SikeParamP503.java
│ ├── SikeParamP610.java
│ └── SikeParamP751.java
│ └── util
│ ├── ByteEncoding.java
│ ├── OctetEncoding.java
│ ├── Sha3.java
│ └── SideChannelUtil.java
└── test
├── java
└── com
│ └── wultra
│ └── security
│ └── pqc
│ └── sike
│ ├── KeyConversionTest.java
│ ├── OctetEncodingTest.java
│ ├── SidhReferenceTest.java
│ ├── SidhTest.java
│ ├── SikeDeterministicTest.java
│ ├── SikeRandomTest.java
│ ├── kat
│ ├── KatP434Test.java
│ ├── KatP503Test.java
│ ├── KatP610Test.java
│ ├── KatP751Test.java
│ ├── KatTester.java
│ ├── model
│ │ ├── KatRspFile.java
│ │ └── KatRspRecord.java
│ └── util
│ │ └── CrtDrbgRandom.java
│ └── math
│ ├── Fp2MathTest.java
│ ├── FpMathTest.java
│ └── UnsignedLongTest.java
└── resources
└── kat
├── PQCkemKAT_374.rsp
├── PQCkemKAT_434.rsp
├── PQCkemKAT_524.rsp
└── PQCkemKAT_644.rsp
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | name: "CodeQL"
7 |
8 | on:
9 | push:
10 | branches: [develop, master]
11 | pull_request:
12 | # The branches below must be a subset of the branches above
13 | branches: [develop]
14 | schedule:
15 | - cron: '0 3 * * 2'
16 |
17 | jobs:
18 | analyze:
19 | name: Analyze
20 | runs-on: ubuntu-latest
21 |
22 | strategy:
23 | fail-fast: false
24 | matrix:
25 | # Override automatic language detection by changing the below list
26 | # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
27 | language: ['java']
28 | # Learn more...
29 | # https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
30 |
31 | steps:
32 | - name: Checkout repository
33 | uses: actions/checkout@v2
34 | with:
35 | # We must fetch at least the immediate parents so that if this is
36 | # a pull request then we can checkout the head.
37 | fetch-depth: 2
38 |
39 | # If this run was triggered by a pull request event, then checkout
40 | # the head of the pull request instead of the merge commit.
41 | - run: git checkout HEAD^2
42 | if: ${{ github.event_name == 'pull_request' }}
43 |
44 | # Initializes the CodeQL tools for scanning.
45 | - name: Initialize CodeQL
46 | uses: github/codeql-action/init@v1
47 | with:
48 | languages: ${{ matrix.language }}
49 | # If you wish to specify custom queries, you can do so here or in a config file.
50 | # By default, queries listed here will override any specified in a config file.
51 | # Prefix the list here with "+" to use these queries and those in the config file.
52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
53 |
54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
55 | # If this step fails, then you should remove it and run the build manually (see below)
56 | - name: Autobuild
57 | uses: github/codeql-action/autobuild@v1
58 |
59 | # ℹ️ Command-line programs to run using the OS shell.
60 | # 📚 https://git.io/JvXDl
61 |
62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
63 | # and modify them (or add more) to build your code if your project
64 | # uses a compiled language
65 |
66 | #- run: |
67 | # make bootstrap
68 | # make release
69 |
70 | - name: Perform CodeQL Analysis
71 | uses: github/codeql-action/analyze@v1
72 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | **/.DS_Store
2 | **/target/
3 | **/src/main/java/generated/
4 | **/.springBeans
5 |
6 | ### NetBeans template
7 | **/nbproject/private/
8 | **/nbproject/
9 |
10 | ### Eclipse template
11 | **/.settings
12 | **/.project
13 | **/.classpath
14 |
15 | ### JetBrains template
16 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
17 | **/*.iml
18 | ## Directory-based project format:
19 | **/.idea/
20 | **/.mvn
21 | **/dist/
22 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - openjdk11
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | The security fixes are provided for the following versions:
6 |
7 | | Version | Supported |
8 | | ------- | ------------------ |
9 | | 0.1.x | :white_check_mark: |
10 |
11 | ## Reporting a Vulnerability
12 |
13 | In case you find a security issue, please report the incident at [support@wultra.com](mailto:support@wultra.com).
14 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | sike-java-parent
7 | SIKE Parent Project
8 |
9 | com.wultra.security
10 | sike-java-parent
11 | 0.1.0
12 | pom
13 |
14 | 2020
15 |
16 |
17 | Wultra s.r.o.
18 | https://wultra.com/
19 |
20 |
21 |
22 |
23 | GNU Affero General Public License v3.0
24 | https://www.gnu.org/licenses/agpl-3.0.en.html
25 |
26 |
27 |
28 |
29 |
30 | Roman Strobl
31 | roman.strobl@wultra.com
32 |
33 | developer
34 |
35 |
36 |
37 |
38 |
39 | scm:git:https://github.com/wultra/sike-java.git
40 | scm:git:https://github.com/wultra/sike-java.git
41 | https://github.com/wultra/sike-java
42 |
43 |
44 |
45 | Github
46 | https://github.com/wultra/sike-java/issues
47 |
48 |
49 |
50 | sike-java
51 |
52 |
53 |
54 | UTF-8
55 | 1.8
56 | 1.8
57 |
58 |
59 |
60 |
61 |
62 | org.apache.maven.plugins
63 | maven-source-plugin
64 | 3.2.1
65 |
66 |
67 | attach-sources
68 | verify
69 |
70 | jar-no-fork
71 |
72 |
73 |
74 |
75 |
76 | org.apache.maven.plugins
77 | maven-javadoc-plugin
78 | 3.1.1
79 |
80 | false
81 |
82 |
83 |
84 | attach-javadocs
85 |
86 | jar
87 |
88 |
89 |
90 |
91 |
92 | org.apache.maven.plugins
93 | maven-deploy-plugin
94 | 2.8.2
95 |
96 |
97 |
98 |
99 |
100 |
101 | release-sign-artifacts
102 |
103 |
104 | performRelease
105 | true
106 |
107 |
108 |
109 |
110 |
111 | org.apache.maven.plugins
112 | maven-gpg-plugin
113 | 1.6
114 |
115 |
116 | sign-artifacts
117 | verify
118 |
119 | sign
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | disable-java8-doclint
129 |
130 | [1.8,)
131 |
132 |
133 | -Xdoclint:none
134 |
135 |
136 |
137 |
138 |
139 |
140 | ossrh
141 | https://oss.sonatype.org/content/repositories/snapshots/
142 |
143 |
144 | ossrh
145 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
146 |
147 |
148 |
149 |
150 |
--------------------------------------------------------------------------------
/sike-java/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | sike-java
8 | SIKE Java
9 | sike-java
10 | 0.1.0
11 |
12 |
13 | com.wultra.security
14 | sike-java-parent
15 | 0.1.0
16 | ../pom.xml
17 |
18 |
19 | jar
20 |
21 |
22 |
23 | org.bouncycastle
24 | bcprov-jdk15on
25 | 1.67
26 |
27 |
28 | org.junit.jupiter
29 | junit-jupiter
30 | 5.4.2
31 | test
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/crypto/KeyGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.crypto;
18 |
19 | import com.wultra.security.pqc.sike.model.ImplementationType;
20 | import com.wultra.security.pqc.sike.model.MontgomeryCurve;
21 | import com.wultra.security.pqc.sike.model.Party;
22 | import com.wultra.security.pqc.sike.model.SidhPrivateKey;
23 | import com.wultra.security.pqc.sike.param.SikeParam;
24 | import com.wultra.security.pqc.sike.util.ByteEncoding;
25 |
26 | import java.math.BigInteger;
27 | import java.security.*;
28 |
29 | /**
30 | * SIDH and SIKE key generator.
31 | *
32 | * @author Roman Strobl, roman.strobl@wultra.com
33 | */
34 | public class KeyGenerator {
35 |
36 | private final SikeParam sikeParam;
37 | private final RandomGenerator randomGenerator;
38 |
39 | /**
40 | * Key generator constructor.
41 | * @param sikeParam SIKE parameters.
42 | */
43 | public KeyGenerator(SikeParam sikeParam) {
44 | this.sikeParam = sikeParam;
45 | this.randomGenerator = new RandomGenerator();
46 | }
47 |
48 | /**
49 | * Constructor for key generator with alternative random generator.
50 | * @param sikeParam SIKE parameters.
51 | * @param randomGenerator Alternative random generator.
52 | */
53 | public KeyGenerator(SikeParam sikeParam, RandomGenerator randomGenerator) {
54 | this.sikeParam = sikeParam;
55 | this.randomGenerator = randomGenerator;
56 | }
57 |
58 | /**
59 | * Generate a key pair.
60 | * @param party Alice or Bob.
61 | * @return Generated key pair.
62 | * @throws GeneralSecurityException Thrown in case cryptography fails.
63 | */
64 | public KeyPair generateKeyPair(Party party) throws GeneralSecurityException {
65 | PrivateKey privateKey = generatePrivateKey(party);
66 | PublicKey publicKey = derivePublicKey(party, privateKey);
67 | return new KeyPair(publicKey, privateKey);
68 | }
69 |
70 | /**
71 | * Generate a private key.
72 | * @param party Alice or Bob.
73 | * @return Generated key pair.
74 | * @throws GeneralSecurityException Thrown in case cryptography fails.
75 | */
76 | public PrivateKey generatePrivateKey(Party party) throws GeneralSecurityException {
77 | byte[] s = randomGenerator.generateRandomBytes(sikeParam.getMessageBytes());
78 | BigInteger randomKey = generateRandomKey(sikeParam, party);
79 | return new SidhPrivateKey(sikeParam, party, randomKey, s);
80 | }
81 |
82 | /**
83 | * Derive public key from a private key.
84 | * @param party Alice or Bob.
85 | * @param privateKey Private key.
86 | * @return Derived public key.
87 | * @throws InvalidKeyException Thrown in case key derivation fails.
88 | */
89 | public PublicKey derivePublicKey(Party party, PrivateKey privateKey) throws InvalidKeyException {
90 | if (!(privateKey instanceof SidhPrivateKey)) {
91 | throw new InvalidKeyException("Invalid private key");
92 | }
93 | SidhPrivateKey priv = (SidhPrivateKey) privateKey;
94 | MontgomeryCurve curve;
95 | if (sikeParam.getImplementationType() == ImplementationType.REFERENCE) {
96 | curve = new MontgomeryCurve(sikeParam, sikeParam.getA(), sikeParam.getB());
97 | } else if (sikeParam.getImplementationType() == ImplementationType.OPTIMIZED) {
98 | curve = new MontgomeryCurve(sikeParam, sikeParam.getA());
99 | } else {
100 | throw new InvalidParameterException("Unsupported implementation type");
101 | }
102 | if (party == Party.ALICE) {
103 | return sikeParam.getIsogeny().isoGen2(curve, priv);
104 | } else if (party == Party.BOB) {
105 | return sikeParam.getIsogeny().isoGen3(curve, priv);
106 | }
107 | throw new InvalidParameterException("Invalid party");
108 | }
109 |
110 | /**
111 | * Generate a random key.
112 | * @param sikeParam SIKE parameters.
113 | * @return Random BigInteger usable as a private key.
114 | * @throws GeneralSecurityException Thrown in case cryptography fails.
115 | */
116 | private BigInteger generateRandomKey(SikeParam sikeParam, Party party) throws GeneralSecurityException {
117 | if (party == Party.ALICE) {
118 | // random value in [0, 2^eA - 1]
119 | int length = (sikeParam.getBitsA() + 7) / 8;
120 | byte[] randomBytes = randomGenerator.generateRandomBytes(length);
121 | randomBytes[randomBytes.length - 1] &= sikeParam.getMaskA();
122 | return ByteEncoding.fromByteArray(randomBytes);
123 | }
124 | if (party == Party.BOB) {
125 | // random value in [0, 2^Floor(Log(2,3^eB)) - 1]
126 | int length = (sikeParam.getBitsB() - 1 + 7) / 8;
127 | byte[] randomBytes = randomGenerator.generateRandomBytes(length);
128 | randomBytes[randomBytes.length - 1] &= sikeParam.getMaskB();
129 | return ByteEncoding.fromByteArray(randomBytes);
130 | }
131 | throw new InvalidParameterException("Invalid party");
132 | }
133 |
134 | }
135 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/crypto/RandomGenerator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.crypto;
18 |
19 | import java.security.NoSuchAlgorithmException;
20 | import java.security.NoSuchProviderException;
21 | import java.security.SecureRandom;
22 |
23 | /**
24 | * Random generator for key material.
25 | *
26 | * @author Roman Strobl, roman.strobl@wultra.com
27 | */
28 | public class RandomGenerator {
29 |
30 | private volatile SecureRandom secureRandom;
31 |
32 | /**
33 | * Default random generator constructor.
34 | */
35 | public RandomGenerator() {
36 | }
37 |
38 | /**
39 | * Random generator constructor with provided SecureRandom.
40 | * @param secureRandom SecureRandom implementation to use.
41 | */
42 | public RandomGenerator(SecureRandom secureRandom) {
43 | this.secureRandom = secureRandom;
44 | }
45 |
46 | /**
47 | * Generate random bytes.
48 | * @param length Length of generated byte array.
49 | * @return Byte array with random bytes.
50 | * @throws NoSuchProviderException Thrown in case Bouncy Castle provider is not available.
51 | * @throws NoSuchAlgorithmException Thrown in case random generator algorithm is not available.
52 | */
53 | public byte[] generateRandomBytes(int length) throws NoSuchProviderException, NoSuchAlgorithmException {
54 | // Double-check locking, see: https://rules.sonarsource.com/java/tag/multi-threading/RSPEC-2168
55 | SecureRandom localSecureRandom = secureRandom;
56 |
57 | if (localSecureRandom == null) {
58 | synchronized (this) {
59 | localSecureRandom = secureRandom;
60 | if (localSecureRandom == null)
61 | // Use SecureRandom implementation from Bouncy Castle library, it is slower,
62 | // however it reseeds periodically and it is quantum safe. The initialization is lazy
63 | // to allow dynamic Bouncy Castle provider initialization and to allow instantiation
64 | // of this class in fields.
65 | secureRandom = localSecureRandom = SecureRandom.getInstance("DEFAULT", "BC");
66 | }
67 | }
68 |
69 | byte[] randomBytes = new byte[length];
70 | localSecureRandom.nextBytes(randomBytes);
71 | return randomBytes;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/crypto/Sidh.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.crypto;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.model.Party;
21 | import com.wultra.security.pqc.sike.model.SidhPrivateKey;
22 | import com.wultra.security.pqc.sike.model.SidhPublicKey;
23 | import com.wultra.security.pqc.sike.param.SikeParam;
24 |
25 | import java.security.*;
26 |
27 | /**
28 | * SIDH key exchange.
29 | *
30 | * @author Roman Strobl, roman.strobl@wultra.com
31 | */
32 | public class Sidh {
33 |
34 | private final SikeParam sikeParam;
35 |
36 | /**
37 | * SIDH key exchange constructor.
38 | * @param sikeParam SIKE parameters.
39 | */
40 | public Sidh(SikeParam sikeParam) {
41 | this.sikeParam = sikeParam;
42 | }
43 |
44 | /**
45 | * Generate a shared secret isogeny j-invariant.
46 | * @param party Alice or Bob.
47 | * @param privateKey Private key.
48 | * @param publicKey Public key.
49 | * @return Shared secret isogeny j-invariant.
50 | * @throws GeneralSecurityException Thrown in case cryptography fails.
51 | */
52 | public Fp2Element generateSharedSecret(Party party, PrivateKey privateKey, PublicKey publicKey) throws GeneralSecurityException {
53 | if (!(privateKey instanceof SidhPrivateKey)) {
54 | throw new InvalidKeyException("Invalid private key");
55 | }
56 | if (!(publicKey instanceof SidhPublicKey)) {
57 | throw new InvalidKeyException("Invalid public key");
58 | }
59 | SidhPrivateKey priv = (SidhPrivateKey) privateKey;
60 | SidhPublicKey pub = (SidhPublicKey) publicKey;
61 | if (party == Party.ALICE) {
62 | return sikeParam.getIsogeny().isoEx2(sikeParam, priv.getKey(), pub.getPx(), pub.getQx(), pub.getRx());
63 | }
64 | if (party == Party.BOB) {
65 | return sikeParam.getIsogeny().isoEx3(sikeParam, priv.getKey(), pub.getPx(), pub.getQx(), pub.getRx());
66 | }
67 | throw new InvalidParameterException("Invalid party");
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/crypto/Sike.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.crypto;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.model.*;
21 | import com.wultra.security.pqc.sike.param.SikeParam;
22 | import com.wultra.security.pqc.sike.util.ByteEncoding;
23 | import com.wultra.security.pqc.sike.util.Sha3;
24 |
25 | import java.math.BigInteger;
26 | import java.security.*;
27 |
28 | /**
29 | * SIKE key encapsulation.
30 | *
31 | * @author Roman Strobl, roman.strobl@wultra.com
32 | */
33 | public class Sike {
34 |
35 | private final SikeParam sikeParam;
36 | private final RandomGenerator randomGenerator;
37 | private final KeyGenerator keyGenerator;
38 | private final Sidh sidh;
39 |
40 | /**
41 | * SIKE key encapsulation constructor.
42 | * @param sikeParam SIKE parameters.
43 | */
44 | public Sike(SikeParam sikeParam) {
45 | this.sikeParam = sikeParam;
46 | this.randomGenerator = new RandomGenerator();
47 | keyGenerator = new KeyGenerator(sikeParam);
48 | sidh = new Sidh(sikeParam);
49 | }
50 |
51 | /**
52 | * SIKE key encapsulation constructor with specified SecureRandom.
53 | * @param sikeParam SIKE parameters.
54 | * @param secureRandom SecureRandom to use.
55 | */
56 | public Sike(SikeParam sikeParam, SecureRandom secureRandom) {
57 | this.sikeParam = sikeParam;
58 | this.randomGenerator = new RandomGenerator(secureRandom);
59 | keyGenerator = new KeyGenerator(sikeParam, randomGenerator);
60 | sidh = new Sidh(sikeParam);
61 | }
62 |
63 | /**
64 | * SIKE encapsulation.
65 | * @param pk3 Bob's public key.
66 | * @return Encapsulation result with shared secret and encrypted message.
67 | * @throws GeneralSecurityException Thrown in case cryptography fails.
68 | */
69 | public EncapsulationResult encapsulate(PublicKey pk3) throws GeneralSecurityException {
70 | if (!(pk3 instanceof SidhPublicKey)) {
71 | throw new InvalidKeyException("Invalid public key");
72 | }
73 | byte[] m = randomGenerator.generateRandomBytes(sikeParam.getMessageBytes());
74 | byte[] r = generateR(m, pk3.getEncoded());
75 | EncryptedMessage encrypted = encrypt(pk3, m, r);
76 | SidhPublicKey c0Key = (SidhPublicKey) encrypted.getC0();
77 | byte[] k = generateK(m, c0Key.getEncoded(), encrypted.getC1());
78 | return new EncapsulationResult(k, encrypted);
79 | }
80 |
81 | /**
82 | * SIKE decapsulation.
83 | * @param sk3 Bob's private key.
84 | * @param pk3 Bob's public key.
85 | * @param encrypted Encrypted message received from Alice.
86 | * @return Shared secret.
87 | * @throws GeneralSecurityException Thrown in case cryptography fails.
88 | */
89 | public byte[] decapsulate(PrivateKey sk3, PublicKey pk3, EncryptedMessage encrypted) throws GeneralSecurityException {
90 | if (!(sk3 instanceof SidhPrivateKey)) {
91 | throw new InvalidKeyException("Invalid private key");
92 | }
93 | if (!(pk3 instanceof SidhPublicKey)) {
94 | throw new InvalidKeyException("Invalid public key");
95 | }
96 | if (encrypted == null) {
97 | throw new InvalidParameterException("Encrypted message is null");
98 | }
99 | if (encrypted.getC0() == null) {
100 | throw new InvalidParameterException("Invalid parameter c0");
101 | }
102 | if (encrypted.getC1() == null) {
103 | throw new InvalidParameterException("Invalid parameter c1");
104 | }
105 | SidhPrivateKey priv3 = (SidhPrivateKey) sk3;
106 | if (priv3.getS() == null) {
107 | throw new InvalidParameterException("Private key cannot be used for decapsulation");
108 | }
109 | byte[] m = decrypt(sk3, encrypted);
110 | byte[] r = generateR(m, pk3.getEncoded());
111 | BigInteger modulo = new BigInteger("2").pow(sikeParam.getEA());
112 | BigInteger key = ByteEncoding.fromByteArray(r).mod(modulo);
113 | PrivateKey rKey = new SidhPrivateKey(sikeParam, Party.ALICE, key);
114 | PublicKey c0Key = keyGenerator.derivePublicKey(Party.ALICE, rKey);
115 | byte[] k;
116 | // The public key equals method runs in constant time
117 | if (c0Key.equals(encrypted.getC0())) {
118 | k = generateK(m, c0Key.getEncoded(), encrypted.getC1());
119 | } else {
120 | k = generateK(priv3.getS(), c0Key.getEncoded(), encrypted.getC1());
121 | }
122 | return k;
123 | }
124 |
125 | /**
126 | * Encrypt a message.
127 | * @param pk3 Bob's public key.
128 | * @param m Message to encrypt, the message size must correspond to the SIKE parameter messageBytes.
129 | * @return Encrypted message.
130 | * @throws GeneralSecurityException Thrown in case cryptography fails.
131 | */
132 | public EncryptedMessage encrypt(PublicKey pk3, byte[] m) throws GeneralSecurityException {
133 | return encrypt(pk3, m, null);
134 | }
135 |
136 | /**
137 | * Encrypt a message.
138 | * @param pk3 Bob's public key.
139 | * @param m Message to encrypt, the message size must correspond to the SIKE parameter messageBytes.
140 | * @param r Optional byte representation of Alice's private key used in SIKE encapsulation.
141 | * @return Encrypted message.
142 | * @throws GeneralSecurityException Thrown in case cryptography fails.
143 | */
144 | private EncryptedMessage encrypt(PublicKey pk3, byte[] m, byte[] r) throws GeneralSecurityException {
145 | if (!(pk3 instanceof SidhPublicKey)) {
146 | throw new InvalidKeyException("Invalid public key");
147 | }
148 | if (m == null || m.length != sikeParam.getMessageBytes()) {
149 | throw new InvalidParameterException("Invalid message");
150 | }
151 | PrivateKey sk2;
152 | if (r == null) {
153 | // Generate ephemeral private key
154 | sk2 = keyGenerator.generatePrivateKey(Party.ALICE);
155 | } else {
156 | // Convert value r into private key
157 | BigInteger modulo = new BigInteger("2").pow(sikeParam.getEA());
158 | BigInteger key = ByteEncoding.fromByteArray(r).mod(modulo);
159 | sk2 = new SidhPrivateKey(sikeParam, Party.ALICE, key);
160 | }
161 | PublicKey c0 = keyGenerator.derivePublicKey(Party.ALICE, sk2);
162 | Fp2Element j = sidh.generateSharedSecret(Party.ALICE, sk2, pk3);
163 | byte[] h = Sha3.shake256(j.getEncoded(), sikeParam.getMessageBytes());
164 | byte[] c1 = new byte[sikeParam.getMessageBytes()];
165 | for (int i = 0; i < sikeParam.getMessageBytes(); i++) {
166 | c1[i] = (byte) (h[i] ^ m[i]);
167 | }
168 | return new EncryptedMessage(c0, c1);
169 | }
170 |
171 | /**
172 | * Decrypt a message.
173 | * @param sk3 Bob's private key.
174 | * @param encrypted Encrypted message received from Alice.
175 | * @return Decrypted message.
176 | * @throws GeneralSecurityException Thrown in case cryptography fails.
177 | */
178 | public byte[] decrypt(PrivateKey sk3, EncryptedMessage encrypted) throws GeneralSecurityException {
179 | if (!(sk3 instanceof SidhPrivateKey)) {
180 | throw new InvalidKeyException("Invalid private key");
181 | }
182 | if (encrypted == null) {
183 | throw new InvalidParameterException("Encrypted message is null");
184 | }
185 | PublicKey c0 = encrypted.getC0();
186 | if (!(c0 instanceof SidhPublicKey)) {
187 | throw new InvalidKeyException("Invalid public key");
188 | }
189 | byte[] c1 = encrypted.getC1();
190 | if (c1 == null) {
191 | throw new InvalidParameterException("Invalid parameter c1");
192 | }
193 | Fp2Element j = sidh.generateSharedSecret(Party.BOB, sk3, c0);
194 | byte[] h = Sha3.shake256(j.getEncoded(), sikeParam.getMessageBytes());
195 | byte[] m = new byte[sikeParam.getMessageBytes()];
196 | for (int i = 0; i < sikeParam.getMessageBytes(); i++) {
197 | m[i] = (byte) (h[i] ^ c1[i]);
198 | }
199 | return m;
200 | }
201 |
202 | /**
203 | * Generate the ephemeral private key r.
204 | * @param m Nonce.
205 | * @param pk3Enc Public key pk3 encoded in bytes.
206 | * @return Ephemeral private key r encoded in bytes.
207 | */
208 | private byte[] generateR(byte[] m, byte[] pk3Enc) {
209 | byte[] dataR = new byte[(m.length + pk3Enc.length)];
210 | System.arraycopy(m, 0, dataR, 0, m.length);
211 | System.arraycopy(pk3Enc, 0, dataR, m.length, pk3Enc.length);
212 | return Sha3.shake256(dataR, (sikeParam.getBitsA() + 7) / 8);
213 | }
214 |
215 | /**
216 | * Generate the shared secret K.
217 | * @param m Nonce.
218 | * @param c0 Public key bytes.
219 | * @param c1 Encrypted message bytes.
220 | * @return Shared secret bytes.
221 | */
222 | private byte[] generateK(byte[] m, byte[] c0, byte[] c1) {
223 | byte[] dataK = new byte[(m.length + c0.length + c1.length)];
224 | System.arraycopy(m, 0, dataK, 0, m.length);
225 | System.arraycopy(c0, 0, dataK, m.length, c0.length);
226 | System.arraycopy(c1, 0, dataK, m.length + c0.length, c1.length);
227 | return Sha3.shake256(dataK, sikeParam.getCryptoBytes());
228 | }
229 |
230 | }
231 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/api/Fp2Element.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.api;
18 |
19 | import java.math.BigInteger;
20 |
21 | /**
22 | * Element of a quadratic extension field F(p^2): x0 + x1*i.
23 | *
24 | * @author Roman Strobl, roman.strobl@wultra.com
25 | */
26 | public interface Fp2Element {
27 |
28 | /**
29 | * Get the real part of element.
30 | * @return Real part of element.
31 | */
32 | FpElement getX0();
33 |
34 | /**
35 | * Get the imaginary part of element.
36 | * @return Imaginary part of element.
37 | */
38 | FpElement getX1();
39 |
40 | /**
41 | * Add two elements.
42 | * @param y Other element.
43 | * @return Calculation result.
44 | */
45 | Fp2Element add(Fp2Element y);
46 |
47 | /**
48 | * Subtract two elements.
49 | * @param y Other element.
50 | * @return Calculation result.
51 | */
52 | Fp2Element subtract(Fp2Element y);
53 |
54 | /**
55 | * Multiply two elements.
56 | * @param y Other element.
57 | * @return Calculation result.
58 | */
59 | Fp2Element multiply(Fp2Element y);
60 |
61 | /**
62 | * Multiply by the imaginary part of the element.
63 | * @return Calculation result.
64 | */
65 | Fp2Element multiplyByI();
66 |
67 | /**
68 | * Square the element.
69 | * @return Calculation result.
70 | */
71 | Fp2Element square();
72 |
73 | /**
74 | * Element exponentiation.
75 | * @param n Exponent
76 | * @return Calculation result.
77 | */
78 | Fp2Element pow(BigInteger n);
79 |
80 | /**
81 | * Calculate the square root of the element.
82 | * @return Calculation result.
83 | */
84 | Fp2Element sqrt();
85 |
86 | /**
87 | * Invert the element.
88 | * @return Calculation result.
89 | */
90 | Fp2Element inverse();
91 |
92 | /**
93 | * Negate the element.
94 | * @return Calculation result.
95 | */
96 | Fp2Element negate();
97 |
98 | /**
99 | * Get whether the element is the zero element.
100 | * @return Whether the element is the zero element.
101 | */
102 | boolean isZero();
103 |
104 | /**
105 | * Copy the element.
106 | * @return Element copy.
107 | */
108 | Fp2Element copy();
109 |
110 | /**
111 | * Encode the element in bytes.
112 | * @return Encoded element in bytes.
113 | */
114 | byte[] getEncoded();
115 |
116 | /**
117 | * Convert element to octet string.
118 | * @return Octet string.
119 | */
120 | String toOctetString();
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/api/Fp2ElementFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.api;
18 |
19 | import java.math.BigInteger;
20 |
21 | /**
22 | * Factory for elements of quadratic extension field F(p^2).
23 | *
24 | * @author Roman Strobl, roman.strobl@wultra.com
25 | */
26 | public interface Fp2ElementFactory {
27 |
28 | /**
29 | * Construct the zero element 0 + 0*i.
30 | * @return Zero element.
31 | */
32 | Fp2Element zero();
33 |
34 | /**
35 | * Construct the one element 1 + 0*i.
36 | * @return One element.
37 | */
38 | Fp2Element one();
39 |
40 | /**
41 | * Generate an element with value x0r + 0*i.
42 | * @param x0r Integer value for the real part of element.
43 | * @return Generated element.
44 | */
45 | Fp2Element generate(BigInteger x0r);
46 |
47 | /**
48 | * Generate an element with value x0r + x0i*i.
49 | * @param x0r Integer value for the real part of element.
50 | * @param x0i Integer value for the imaginary part of element.
51 | * @return Generated element.
52 | */
53 | Fp2Element generate(BigInteger x0r, BigInteger x0i);
54 | }
55 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/api/Fp2Point.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.api;
18 |
19 | /**
20 | * Point in F(p^2) with unspecified coordinate system.
21 | *
22 | * @author Roman Strobl, roman.strobl@wultra.com
23 | */
24 | public interface Fp2Point {
25 |
26 | /**
27 | * Get the x coordinate.
28 | * @return The x coordinate.
29 | */
30 | Fp2Element getX();
31 |
32 | /**
33 | * Get the y coordinate.
34 | * @return The y coordinate.
35 | */
36 | Fp2Element getY();
37 |
38 | /**
39 | * Get the z coordinate.
40 | * @return The z coordinate.
41 | */
42 | Fp2Element getZ();
43 |
44 | /**
45 | * Add two points.
46 | * @param o Other point.
47 | * @return Result of point addition.
48 | */
49 | Fp2Point add(Fp2Point o);
50 |
51 | /**
52 | * Subtract two points.
53 | * @param o Other point.
54 | * @return Result of point subtraction.
55 | */
56 | Fp2Point subtract(Fp2Point o);
57 |
58 | /**
59 | * Multiply two points.
60 | * @param o Other point.
61 | * @return Result of point multiplication.
62 | */
63 | Fp2Point multiply(Fp2Point o);
64 |
65 | /**
66 | * Square a point.
67 | * @return Result of a square operation.
68 | */
69 | Fp2Point square();
70 |
71 | /**
72 | * Invert a point.
73 | * @return Result of an inversion operation.
74 | */
75 | Fp2Point inverse();
76 |
77 | /**
78 | * Negate a point.
79 | * @return Result of a negation operation.
80 | */
81 | Fp2Point negate();
82 |
83 | /**
84 | * Get whether this is a point at infinity.
85 | * @return Whether this is a point at infinity.
86 | */
87 | boolean isInfinite();
88 |
89 | /**
90 | * Copy the point.
91 | * @return Point copy.
92 | */
93 | Fp2Point copy();
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/api/FpElement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.api;
18 |
19 | import java.math.BigInteger;
20 |
21 | /**
22 | * Element of an F(p) field with a single coordinate x.
23 | *
24 | * @author Roman Strobl, roman.strobl@wultra.com
25 | */
26 | public interface FpElement {
27 |
28 | /**
29 | * Get the element value.
30 | * @return the element value.
31 | */
32 | BigInteger getX();
33 |
34 | /**
35 | * Add two elements.
36 | * @param o Other element.
37 | * @return Calculation result.
38 | */
39 | FpElement add(FpElement o);
40 |
41 | /**
42 | * Subtract two elements.
43 | * @param o Other element.
44 | * @return Calculation result.
45 | */
46 | FpElement subtract(FpElement o);
47 |
48 | /**
49 | * Multiply two elements.
50 | * @param o Other element.
51 | * @return Calculation result.
52 | */
53 | FpElement multiply(FpElement o);
54 |
55 | /**
56 | * Square the elements.
57 | * @return Calculation result.
58 | */
59 | FpElement square();
60 | /**
61 | * Invert the element.
62 | * @return Calculation result.
63 | */
64 | FpElement inverse();
65 |
66 | /**
67 | * Negate the element.
68 | * @return Calculation result.
69 | */
70 | FpElement negate();
71 |
72 | /**
73 | * Get whether the element is the zero element.
74 | * @return Whether the element is the zero element.
75 | */
76 | boolean isZero();
77 |
78 | /**
79 | * Copy the element.
80 | * @return Element copy.
81 | */
82 | FpElement copy();
83 | /**
84 | * Encode the element in bytes.
85 | * @return Encoded element in bytes.
86 | */
87 | byte[] getEncoded();
88 |
89 | /**
90 | * Convert element to octet string.
91 | * @return Octet string.
92 | */
93 | String toOctetString();
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/api/Isogeny.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.api;
18 |
19 | import com.wultra.security.pqc.sike.model.EvaluatedCurve;
20 | import com.wultra.security.pqc.sike.model.MontgomeryCurve;
21 | import com.wultra.security.pqc.sike.model.SidhPrivateKey;
22 | import com.wultra.security.pqc.sike.model.SidhPublicKey;
23 | import com.wultra.security.pqc.sike.param.SikeParam;
24 |
25 | /**
26 | * Elliptic curve isogeny operations on Montgomery curves.
27 | *
28 | * @author Roman Strobl, roman.strobl@wultra.com
29 | */
30 | public interface Isogeny {
31 |
32 | /**
33 | * Compute a 2-isogenous curve.
34 | * @param curve Current curve.
35 | * @param p2 Generator point with order equal to 2 on current curve.
36 | * @return A 2-isogenous curve.
37 | */
38 | MontgomeryCurve curve2Iso(MontgomeryCurve curve, Fp2Point p2);
39 |
40 | /**
41 | * Compute a 3-isogenous curve.
42 | * @param curve Current curve.
43 | * @param p3 Generator point with order equal to 3 on current curve.
44 | * @return A 3-isogenous curve.
45 | */
46 | MontgomeryCurve curve3Iso(MontgomeryCurve curve, Fp2Point p3);
47 |
48 | /**
49 | * Compute a 4-isogenous curve.
50 | * @param curve Current curve.
51 | * @param p4 Generator point with order equal to 4 on current curve.
52 | * @return A 4-isogenous curve.
53 | */
54 | MontgomeryCurve curve4Iso(MontgomeryCurve curve, Fp2Point p4);
55 |
56 | /**
57 | * Evaluate a 2-isogeny at a point.
58 | * @param q Point to be evaluated.
59 | * @param p2 Generator point with order equal to 2 on current curve.
60 | * @return Evaluated point.
61 | */
62 | Fp2Point eval2Iso(Fp2Point q, Fp2Point p2);
63 |
64 | /**
65 | * Evaluate a 3-isogeny at a point.
66 | * @param curve Current curve.
67 | * @param q Point to be evaluated.
68 | * @param p3 Generator point with order equal to 3 on current curve.
69 | * @return Evaluated point.
70 | */
71 | Fp2Point eval3Iso(MontgomeryCurve curve, Fp2Point q, Fp2Point p3);
72 |
73 | /**
74 | * Evaluate a 4-isogeny at a point.
75 | * @param curve Current curve.
76 | * @param q Point to be evaluated.
77 | * @param p4 Generator point with order equal to 4 on current curve.
78 | * @return Evaluated point.
79 | */
80 | Fp2Point eval4Iso(MontgomeryCurve curve, Fp2Point q, Fp2Point p4);
81 |
82 | /**
83 | * Compute a 2^eA-isogeny and evaluate points p and q on this isogeny.
84 | * @param curve Current curve.
85 | * @param s Generator point with order equal to 2^eA on current curve.
86 | * @param points Points to be evaluated on computed isogeny (optional).
87 | * @return Curve corresponding to a 2^eA-isogeny.
88 | */
89 | EvaluatedCurve iso2e(MontgomeryCurve curve, Fp2Point s, Fp2Point ... points);
90 |
91 | /**
92 | * Compute a 3^eB-isogeny and evaluate points p and q on this isogeny.
93 | * @param curve Current curve.
94 | * @param s Generator point with order equal to 3^eB on current curve.
95 | * @param points Points to be evaluated on computed isogeny (optional).
96 | * @return Curve corresponding to a 3^eB-isogeny.
97 | */
98 | EvaluatedCurve iso3e(MontgomeryCurve curve, Fp2Point s, Fp2Point ... points);
99 |
100 | /**
101 | * Derive a public key from a private key for Alice.
102 | * @param curve Starting curve.
103 | * @param privateKey Private key.
104 | * @return Derived public key.
105 | */
106 | SidhPublicKey isoGen2(MontgomeryCurve curve, SidhPrivateKey privateKey);
107 |
108 | /**
109 | * Derive a public key from a private key for Bob.
110 | * @param curve Starting curve.
111 | * @param privateKey Private key.
112 | * @return Derived public key.
113 | */
114 | SidhPublicKey isoGen3(MontgomeryCurve curve, SidhPrivateKey privateKey);
115 |
116 | /**
117 | * Compute a shared secret isogeny j-invariant in the 2-torsion.
118 | * @param sikeParam SIKE parameters.
119 | * @param sk2 Private key.
120 | * @param p2 The x coordinate of public point P.
121 | * @param q2 The x coordinate of public point Q.
122 | * @param r2 The x coordinate of public point R.
123 | * @return Shared secret isogeny j-invariant.
124 | */
125 | Fp2Element isoEx2(SikeParam sikeParam, byte[] sk2, Fp2Element p2, Fp2Element q2, Fp2Element r2);
126 |
127 | /**
128 | * Compute a shared secret isogeny j-invariant in the 3-torsion.
129 | * @param sikeParam SIKE parameters.
130 | * @param sk3 Private key.
131 | * @param p3 The x coordinate of public point P.
132 | * @param q3 The x coordinate of public point Q.
133 | * @param r3 The x coordinate of public point R.
134 | * @return Shared secret isogeny j-invariant.
135 | */
136 | Fp2Element isoEx3(SikeParam sikeParam, byte[] sk3, Fp2Element p3, Fp2Element q3, Fp2Element r3);
137 |
138 | }
139 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/api/Montgomery.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.api;
18 |
19 | import com.wultra.security.pqc.sike.model.MontgomeryCurve;
20 | import com.wultra.security.pqc.sike.param.SikeParam;
21 |
22 | /**
23 | * Elliptic curve mathematics on Montgomery curves. A common interface for all implementation types
24 | *
25 | * @author Roman Strobl, roman.strobl@wultra.com
26 | */
27 | public interface Montgomery {
28 |
29 | /**
30 | * Double a point.
31 | * @param curve Current curve.
32 | * @param p Point on the curve.
33 | * @return Calculated new point.
34 | */
35 | Fp2Point xDbl(MontgomeryCurve curve, Fp2Point p);
36 |
37 | /**
38 | * Triple a point.
39 | * @param curve Current curve.
40 | * @param p Point on the curve.
41 | * @return Calculated new point.
42 | */
43 | Fp2Point xTpl(MontgomeryCurve curve, Fp2Point p);
44 |
45 | /**
46 | * Repeated doubling of a point.
47 | * @param curve Current curve.
48 | * @param p Point on the curve.
49 | * @param e Number of iterations.
50 | * @return Calculated new point.
51 | */
52 | Fp2Point xDble(MontgomeryCurve curve, Fp2Point p, int e);
53 |
54 | /**
55 | * Repeated trippling of a point.
56 | * @param curve Current curve.
57 | * @param p Point on the curve.
58 | * @param e Number of iterations.
59 | * @return Calculated new point.
60 | */
61 | Fp2Point xTple(MontgomeryCurve curve, Fp2Point p, int e);
62 |
63 | /**
64 | * Calculate a j-invariant of a curve.
65 | * @param curve Current curve.
66 | * @return Calculated j-invariant.
67 | */
68 | Fp2Element jInv(MontgomeryCurve curve);
69 |
70 | /**
71 | * Recover the Montgomery curve coefficient a.
72 | * @param sikeParam SIKE parameters.
73 | * @param px The x coordinate of point P.
74 | * @param qx The x coordinate of point Q.
75 | * @param rx The x coordinate of point R.
76 | * @return Recovered coefficient a.
77 | */
78 | Fp2Element getA(SikeParam sikeParam, Fp2Element px, Fp2Element qx, Fp2Element rx);
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/optimized/Fp2PointProjective.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.optimized;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.math.api.Fp2Point;
21 |
22 | import java.security.InvalidParameterException;
23 | import java.util.Objects;
24 |
25 | /**
26 | * Point with projective coordinates [x:z] in F(p^2).
27 | *
28 | * @author Roman Strobl, roman.strobl@wultra.com
29 | */
30 | public class Fp2PointProjective implements Fp2Point {
31 |
32 | private final Fp2Element x;
33 | private final Fp2Element z;
34 |
35 | /**
36 | * Projective point constructor.
37 | * @param x The x element.
38 | * @param z The z element.
39 | */
40 | public Fp2PointProjective(Fp2Element x, Fp2Element z) {
41 | this.x = x;
42 | this.z = z;
43 | }
44 |
45 | @Override
46 | public Fp2Element getX() {
47 | return x;
48 | }
49 |
50 | /**
51 | * The y coordinate is not defined in projective coordinate system.
52 | */
53 | @Override
54 | public Fp2Element getY() {
55 | throw new InvalidParameterException("Invalid point coordinate");
56 | }
57 |
58 | @Override
59 | public Fp2Element getZ() {
60 | return z;
61 | }
62 |
63 | @Override
64 | public Fp2Point add(Fp2Point o) {
65 | return new Fp2PointProjective(x.add(o.getX()), z.add(o.getY()));
66 | }
67 |
68 | @Override
69 | public Fp2Point subtract(Fp2Point o) {
70 | return new Fp2PointProjective(x.subtract(o.getX()), z.subtract(o.getY()));
71 | }
72 |
73 | @Override
74 | public Fp2Point multiply(Fp2Point o) {
75 | return new Fp2PointProjective(x.multiply(o.getX()), z.multiply(o.getY()));
76 | }
77 |
78 | @Override
79 | public Fp2Point square() {
80 | return multiply(this);
81 | }
82 |
83 | @Override
84 | public Fp2Point inverse() {
85 | return new Fp2PointProjective(x.inverse(), z.inverse());
86 | }
87 |
88 | @Override
89 | public Fp2Point negate() {
90 | throw new RuntimeException("Not implemented yet");
91 | }
92 |
93 | @Override
94 | public boolean isInfinite() {
95 | throw new RuntimeException("Not implemented yet");
96 | }
97 |
98 | @Override
99 | public Fp2Point copy() {
100 | return new Fp2PointProjective(x.copy(), z.copy());
101 | }
102 |
103 | @Override
104 | public String toString() {
105 | return "(" + x.toString() + ", " + z.toString() + ")";
106 | }
107 |
108 | @Override
109 | public boolean equals(Object o) {
110 | if (this == o) return true;
111 | if (o == null || getClass() != o.getClass()) return false;
112 | Fp2PointProjective that = (Fp2PointProjective) o;
113 | // Use & to avoid timing attacks
114 | return x.equals(that.x) & z.equals(that.z);
115 | }
116 |
117 | @Override
118 | public int hashCode() {
119 | return Objects.hash(x, z);
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/optimized/MontgomeryProjective.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.optimized;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.math.api.Fp2Point;
21 | import com.wultra.security.pqc.sike.math.api.Montgomery;
22 | import com.wultra.security.pqc.sike.math.optimized.fp.FpElementOpti;
23 | import com.wultra.security.pqc.sike.model.MontgomeryCurve;
24 | import com.wultra.security.pqc.sike.model.optimized.MontgomeryConstants;
25 | import com.wultra.security.pqc.sike.param.SikeParam;
26 |
27 | /**
28 | * Optimized elliptic curve mathematics on Montgomery curves with projective coordinates.
29 | *
30 | * @author Roman Strobl, roman.strobl@wultra.com
31 | */
32 | public class MontgomeryProjective implements Montgomery {
33 |
34 | @Override
35 | public Fp2Point xDbl(MontgomeryCurve curve, Fp2Point p) {
36 | MontgomeryConstants constants = curve.getOptimizedConstants();
37 | Fp2Element a24plus = constants.getA24plus();
38 | Fp2Element c24 = constants.getC24();
39 | Fp2Element t0, t1, p2x, p2z;
40 | t0 = p.getX().subtract(p.getZ());
41 | t1 = p.getX().add(p.getZ());
42 | t0 = t0.square();
43 | t1 = t1.square();
44 | p2z = c24.multiply(t0);
45 | p2x = p2z.multiply(t1);
46 | t1 = t1.subtract(t0);
47 | t0 = a24plus.multiply(t1);
48 | p2z = p2z.add(t0);
49 | p2z = p2z.multiply(t1);
50 | return new Fp2PointProjective(p2x, p2z);
51 | }
52 |
53 | @Override
54 | public Fp2Point xTpl(MontgomeryCurve curve, Fp2Point p) {
55 | MontgomeryConstants constants = curve.getOptimizedConstants();
56 | Fp2Element a24plus = constants.getA24plus();
57 | Fp2Element a24minus = constants.getA24minus();
58 | Fp2Element t0, t1, t2, t3, t4, t5, t6, p3x, p3z;
59 | t0 = p.getX().subtract(p.getZ());
60 | t2 = t0.square();
61 | t1 = p.getX().add(p.getZ());
62 | t3 = t1.square();
63 | t4 = t1.add(t0);
64 | t0 = t1.subtract(t0);
65 | t1 = t4.square();
66 | t1 = t1.subtract(t3);
67 | t1 = t1.subtract(t2);
68 | // Multiplicands are swapped for faster computation as it is done in official C implementation.
69 | t5 = a24plus.multiply(t3);
70 | t3 = t5.multiply(t3);
71 | t6 = t2.multiply(a24minus);
72 | t2 = t2.multiply(t6);
73 | t3 = t2.subtract(t3);
74 | t2 = t5.subtract(t6);
75 | t1 = t2.multiply(t1);
76 | t2 = t3.add(t1);
77 | t2 = t2.square();
78 | p3x = t2.multiply(t4);
79 | t1 = t3.subtract(t1);
80 | t1 = t1.square();
81 | p3z = t1.multiply(t0);
82 | return new Fp2PointProjective(p3x, p3z);
83 | }
84 |
85 | @Override
86 | public Fp2Point xDble(MontgomeryCurve curve, Fp2Point p, int e) {
87 | Fp2Point pAp = p;
88 | for (int i = 0; i < e; i++) {
89 | pAp = xDbl(curve, pAp);
90 | }
91 | return pAp;
92 | }
93 |
94 | @Override
95 | public Fp2Point xTple(MontgomeryCurve curve, Fp2Point p, int e) {
96 | Fp2Point pAp = p;
97 | for (int i = 0; i < e; i++) {
98 | pAp = xTpl(curve, pAp);
99 | }
100 | return pAp;
101 | }
102 |
103 | @Override
104 | public Fp2Element jInv(MontgomeryCurve curve) {
105 | Fp2Element a = curve.getA();
106 | MontgomeryConstants constants = curve.getOptimizedConstants();
107 | Fp2Element c = constants.getC();
108 | Fp2Element t0, t1, j;
109 | j = a.square();
110 | t1 = c.square();
111 | t0 = t1.add(t1);
112 | t0 = j.subtract(t0);
113 | t0 = t0.subtract(t1);
114 | j = t0.subtract(t1);
115 | t1 = t1.square();
116 | j = j.multiply(t1);
117 | t0 = t0.add(t0);
118 | t0 = t0.add(t0);
119 | t1 = t0.square();
120 | t0 = t0.multiply(t1);
121 | t0 = t0.add(t0);
122 | t0 = t0.add(t0);
123 | j = j.inverse();
124 | j = t0.multiply(j);
125 | return j;
126 | }
127 |
128 | @Override
129 | public Fp2Element getA(SikeParam sikeParam, Fp2Element px, Fp2Element qx, Fp2Element rx) {
130 | Fp2Element t0, t1, ap;
131 | t1 = px.add(qx);
132 | t0 = px.multiply(qx);
133 | ap = rx.multiply(t1);
134 | ap = ap.add(t0);
135 | t0 = t0.multiply(rx);
136 | ap = ap.subtract(sikeParam.getFp2ElementFactory().one());
137 | t0 = t0.add(t0);
138 | t1 = t1.add(rx);
139 | t0 = t0.add(t0);
140 | ap = ap.square();
141 | t0 = t0.inverse();
142 | ap = ap.multiply(t0);
143 | ap = ap.subtract(t1);
144 | return ap;
145 | }
146 |
147 | /**
148 | * Combined coordinate doubling and differential addition.
149 | * @param p Point P.
150 | * @param q Point Q.
151 | * @param r Point P - Q.
152 | * @return Points P2 and P + Q.
153 | */
154 | private Fp2Point[] xDblAdd(Fp2Point p, Fp2Point q, Fp2Point r, Fp2Element a24plus) {
155 | Fp2Element t0, t1, t2, p2x, p2z, pqx, pqz;
156 | t0 = p.getX().add(p.getZ());
157 | t1 = p.getX().subtract(p.getZ());
158 | p2x = t0.square();
159 | t2 = q.getX().subtract(q.getZ());
160 | pqx = q.getX().add(q.getZ());
161 | t0 = t0.multiply(t2);
162 | p2z = t1.square();
163 | t1 = t1.multiply(pqx);
164 | t2 = p2x.subtract(p2z);
165 | p2x = p2x.multiply(p2z);
166 | pqx = a24plus.multiply(t2);
167 | pqz = t0.subtract(t1);
168 | p2z = pqx.add(p2z);
169 | pqx = t0.add(t1);
170 | p2z = p2z.multiply(t2);
171 | pqz = pqz.square();
172 | pqx = pqx.square();
173 | pqz = r.getX().multiply(pqz);
174 | pqx = r.getZ().multiply(pqx);
175 | Fp2PointProjective p2 = new Fp2PointProjective(p2x, p2z);
176 | Fp2PointProjective pq = new Fp2PointProjective(pqx, pqz);
177 | return new Fp2PointProjective[]{p2, pq};
178 | }
179 |
180 | /**
181 | * Three point Montgomery ladder.
182 | * @param curve Current curve.
183 | * @param m Scalar value.
184 | * @param px The x coordinate of point P.
185 | * @param qx The x coordinate of point Q.
186 | * @param rx The x coordinate of point P - Q.
187 | * @param bits Number of bits in field elements.
188 | * @return Calculated new point.
189 | */
190 | public Fp2Point ladder3Pt(MontgomeryCurve curve, byte[] m, Fp2Element px, Fp2Element qx, Fp2Element rx, int bits) {
191 | SikeParam sikeParam = curve.getSikeParam();
192 | Fp2Element a = curve.getA();
193 | Fp2Point r0 = new Fp2PointProjective(qx.copy(), sikeParam.getFp2ElementFactory().one());
194 | Fp2Point r1 = new Fp2PointProjective(px.copy(), sikeParam.getFp2ElementFactory().one());
195 | Fp2Point r2 = new Fp2PointProjective(rx.copy(), sikeParam.getFp2ElementFactory().one());
196 |
197 | // Compute A + 2C / 4C
198 | Fp2Element c = curve.getOptimizedConstants().getC();
199 | Fp2Element c2 = c.add(c);
200 | Fp2Element aPlus2c = a.add(c2);
201 | Fp2Element c4 = c2.add(c2);
202 | Fp2Element c4Inv = c4.inverse();
203 | Fp2Element aPlus2cOver4c = aPlus2c.multiply(c4Inv);
204 |
205 | byte prevBit = 0;
206 | for (int i = 0; i < bits; i++) {
207 | byte bit = (byte) (m[i >>> 3] >>> (i & 7) & 1);
208 | byte swap = (byte) (prevBit ^ bit);
209 | prevBit = bit;
210 | condSwap(sikeParam, r1, r2, swap);
211 | Fp2Point[] points = xDblAdd(r0, r2, r1, aPlus2cOver4c);
212 | r0 = points[0].copy();
213 | r2 = points[1].copy();
214 | }
215 | condSwap(sikeParam, r1, r2, prevBit);
216 | return r1;
217 | }
218 |
219 | /**
220 | * Swap two points conditionally.
221 | * @param sikeParam SIKE parameters.
222 | * @param p Point p.
223 | * @param q Point q.
224 | * @param mask Swap condition, if zero swap is not performed.
225 | */
226 | private void condSwap(SikeParam sikeParam, Fp2Point p, Fp2Point q, long mask) {
227 | FpElementOpti.conditionalSwap(sikeParam, (FpElementOpti) p.getX().getX0(), (FpElementOpti) q.getX().getX0(), mask);
228 | FpElementOpti.conditionalSwap(sikeParam, (FpElementOpti) p.getX().getX1(), (FpElementOpti) q.getX().getX1(), mask);
229 | FpElementOpti.conditionalSwap(sikeParam, (FpElementOpti) p.getZ().getX0(), (FpElementOpti) q.getZ().getX0(), mask);
230 | FpElementOpti.conditionalSwap(sikeParam, (FpElementOpti) p.getZ().getX1(), (FpElementOpti) q.getZ().getX1(), mask);
231 | }
232 |
233 | }
234 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/optimized/fp/Fp2ElementFactoryOpti.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.optimized.fp;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.math.api.Fp2ElementFactory;
21 | import com.wultra.security.pqc.sike.param.SikeParam;
22 |
23 | import java.math.BigInteger;
24 |
25 | /**
26 | * Factory for optimized elements of quadratic extension field F(p^2).
27 | *
28 | * @author Roman Strobl, roman.strobl@wultra.com
29 | */
30 | public class Fp2ElementFactoryOpti implements Fp2ElementFactory {
31 |
32 | private final SikeParam sikeParam;
33 |
34 | /**
35 | * Fp2Element factory constructor for optimized elements.
36 | * @param sikeParam SIKE parameters.
37 | */
38 | public Fp2ElementFactoryOpti(SikeParam sikeParam) {
39 | this.sikeParam = sikeParam;
40 | }
41 |
42 | @Override
43 | public Fp2Element zero() {
44 | return new Fp2ElementOpti(sikeParam, BigInteger.ZERO, BigInteger.ZERO);
45 | }
46 |
47 | @Override
48 | public Fp2Element one() {
49 | return new Fp2ElementOpti(sikeParam, BigInteger.ONE, BigInteger.ZERO);
50 | }
51 |
52 | @Override
53 | public Fp2Element generate(BigInteger x0r) {
54 | return new Fp2ElementOpti(sikeParam, x0r, BigInteger.ZERO);
55 | }
56 |
57 | @Override
58 | public Fp2Element generate(BigInteger x0r, BigInteger x0i) {
59 | return new Fp2ElementOpti(sikeParam, x0r, x0i);
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/optimized/fp/UnsignedLong.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.optimized.fp;
18 |
19 | /**
20 | * Mathematical functions for the 64-bit unsigned integer type.
21 | * All methods are constant time to prevent side channel attacks.
22 | *
23 | * @author Roman Strobl, roman.strobl@wultra.com
24 | */
25 | public class UnsignedLong {
26 |
27 | private UnsignedLong() {
28 |
29 | }
30 |
31 | /**
32 | * Add two unsigned long values with carry.
33 | * @param x First unsigned long value.
34 | * @param y Second unsigned long value.
35 | * @param carry Carry set to 1 in case of overflow, otherwise 0.
36 | * @return Unsigned long addition result.
37 | */
38 | public static long[] add(long x, long y, long carry) {
39 | long sum = x + y + carry;
40 | long carryOut = (((x & y) | ((x | y) & ~sum)) >>> 63);
41 | return new long[]{sum, carryOut};
42 | }
43 |
44 | /**
45 | * Subtract two unsigned long values with borrow.
46 | * @param x First unsigned long value.
47 | * @param y Second unsigned long value.
48 | * @param borrow Borrow set to 1 in case of underflow, otherwise 0.
49 | * @return Unsigned long subtraction result.
50 | */
51 | public static long[] sub(long x, long y, long borrow) {
52 | long sub = x - y;
53 | long borrowOut = (borrow & (1 ^ ((sub | -sub) >>> 63))) | (x ^ ((x ^ y) | ((x - y) ^ y))) >>> 63;
54 | long diff = sub - borrow;
55 | return new long[]{diff, borrowOut};
56 | }
57 |
58 | /**
59 | * Multiply two unsigned long values.
60 | * @param x First unsigned long value.
61 | * @param y Second unsigned long value.
62 | * @return Result of multiplication of two unsigned longs, represented by their hi and lo values, each 64-bit.
63 | */
64 | public static long[] mul(long x, long y) {
65 | long al, bl, ah, bh, albl, albh, ahbl, ahbh;
66 | long res1, res2, res3;
67 | long carry, temp;
68 | long maskL = 0L, maskH;
69 | long lo, hi;
70 |
71 | maskL = (~maskL) >>> 32;
72 | maskH = ~maskL;
73 |
74 | al = x & maskL;
75 | ah = x >>> 32;
76 | bl = y & maskL;
77 | bh = y >>> 32;
78 |
79 | albl = al * bl;
80 | albh = al * bh;
81 | ahbl = ah * bl;
82 | ahbh = ah * bh;
83 | lo = albl & maskL;
84 |
85 | res1 = albl >>> 32;
86 | res2 = ahbl & maskL;
87 | res3 = albh & maskL;
88 | temp = res1 + res2 + res3;
89 | carry = temp >>> 32;
90 | lo ^= temp << 32;
91 |
92 | res1 = ahbl >>> 32;
93 | res2 = albh >>> 32;
94 | res3 = ahbh & maskL;
95 | temp = res1 + res2 + res3 + carry;
96 | hi = temp & maskL;
97 | carry = temp & maskH;
98 | hi ^= (ahbh & maskH) + carry;
99 | return new long[]{hi, lo};
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/reference/Fp2PointAffine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.reference;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.math.api.Fp2Point;
21 | import com.wultra.security.pqc.sike.param.SikeParam;
22 |
23 | import java.security.InvalidParameterException;
24 | import java.util.Objects;
25 |
26 | /**
27 | * Point with affine coordinates [x:y] in F(p^2).
28 | *
29 | * @author Roman Strobl, roman.strobl@wultra.com
30 | */
31 | public class Fp2PointAffine implements Fp2Point {
32 |
33 | private final Fp2Element x;
34 | private final Fp2Element y;
35 |
36 | /**
37 | * Affine point constructor.
38 | * @param x The x element.
39 | * @param y The y element.
40 | */
41 | public Fp2PointAffine(Fp2Element x, Fp2Element y) {
42 | this.x = x;
43 | this.y = y;
44 | }
45 |
46 | /**
47 | * Construct point at infinity.
48 | * @param sikeParam SIKE parameters.
49 | * @return Point at infinity.
50 | */
51 | public static Fp2Point infinity(SikeParam sikeParam) {
52 | Fp2Element zero = sikeParam.getFp2ElementFactory().zero();
53 | return new Fp2PointAffine(zero, zero);
54 | }
55 |
56 | @Override
57 | public Fp2Element getX() {
58 | return x;
59 | }
60 |
61 | @Override
62 | public Fp2Element getY() {
63 | return y;
64 | }
65 |
66 | /**
67 | * The z coordinate is not defined in affine coordinate system.
68 | */
69 | @Override
70 | public Fp2Element getZ() {
71 | throw new InvalidParameterException("Invalid point coordinate");
72 | }
73 |
74 | @Override
75 | public Fp2Point add(Fp2Point o) {
76 | return new Fp2PointAffine(x.add(o.getX()), y.add(o.getY()));
77 | }
78 |
79 | @Override
80 | public Fp2Point subtract(Fp2Point o) {
81 | return new Fp2PointAffine(x.subtract(o.getX()), y.subtract(o.getY()));
82 | }
83 |
84 | @Override
85 | public Fp2Point multiply(Fp2Point o) {
86 | return new Fp2PointAffine(x.multiply(o.getX()), y.multiply(o.getY()));
87 | }
88 |
89 | @Override
90 | public Fp2Point square() {
91 | return multiply(this);
92 | }
93 |
94 | @Override
95 | public Fp2Point inverse() {
96 | return new Fp2PointAffine(x.inverse(), y.inverse());
97 | }
98 |
99 | @Override
100 | public Fp2Point negate() {
101 | return new Fp2PointAffine(x, y.negate());
102 | }
103 |
104 | @Override
105 | public boolean isInfinite() {
106 | return y.isZero();
107 | }
108 |
109 | @Override
110 | public Fp2Point copy() {
111 | return new Fp2PointAffine(x.copy(), y.copy());
112 | }
113 |
114 | public String toString() {
115 | return "(" + x.toString() + ", " + y.toString() + ")";
116 | }
117 |
118 | @Override
119 | public boolean equals(Object o) {
120 | if (this == o) return true;
121 | if (o == null || getClass() != o.getClass()) return false;
122 | Fp2PointAffine that = (Fp2PointAffine) o;
123 | return x.equals(that.x) &&
124 | y.equals(that.y);
125 | }
126 |
127 | @Override
128 | public int hashCode() {
129 | return Objects.hash(x, y);
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/reference/MontgomeryAffine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.reference;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.math.api.Fp2Point;
21 | import com.wultra.security.pqc.sike.math.api.Montgomery;
22 | import com.wultra.security.pqc.sike.model.EvaluatedCurve;
23 | import com.wultra.security.pqc.sike.model.MontgomeryCurve;
24 | import com.wultra.security.pqc.sike.param.SikeParam;
25 |
26 | import java.math.BigInteger;
27 |
28 | /**
29 | * Reference elliptic curve mathematics on Montgomery curves with affine coordinates.
30 | *
31 | * @author Roman Strobl, roman.strobl@wultra.com
32 | */
33 | public class MontgomeryAffine implements Montgomery {
34 |
35 | @Override
36 | public Fp2Point xDbl(MontgomeryCurve curve, Fp2Point p) {
37 | if (p.isInfinite()) {
38 | return p;
39 | }
40 |
41 | Fp2Element t0, t1, t2, x2p, y2p;
42 | Fp2Element b = curve.getB();
43 | SikeParam sikeParam = curve.getSikeParam();
44 |
45 | t0 = p.getX().square();
46 | t1 = t0.add(t0);
47 | t2 = sikeParam.getFp2ElementFactory().one();
48 | t0 = t0.add(t1);
49 | t1 = curve.getA().multiply(p.getX());
50 | t1 = t1.add(t1);
51 | t0 = t0.add(t1);
52 | t0 = t0.add(t2);
53 | t1 = b.multiply(p.getY());
54 | t1 = t1.add(t1);
55 | t1 = t1.inverse();
56 | t0 = t0.multiply(t1);
57 | t1 = t0.square();
58 | t2 = b.multiply(t1);
59 | t2 = t2.subtract(curve.getA());
60 | t2 = t2.subtract(p.getX());
61 | t2 = t2.subtract(p.getX());
62 | t1 = t0.multiply(t1);
63 | t1 = b.multiply(t1);
64 | t1 = t1.add(p.getY());
65 | y2p = p.getX().add(p.getX());
66 | y2p = y2p.add(p.getX());
67 | y2p = y2p.add(curve.getA());
68 | y2p = y2p.multiply(t0);
69 | y2p = y2p.subtract(t1);
70 | x2p = t2;
71 | return new Fp2PointAffine(x2p, y2p);
72 | }
73 |
74 | @Override
75 | public Fp2Point xTpl(MontgomeryCurve curve, Fp2Point p) {
76 | Fp2Point p2 = xDbl(curve, p);
77 | return xAdd(curve, p, p2);
78 | }
79 |
80 | @Override
81 | public Fp2Point xDble(MontgomeryCurve curve, Fp2Point p, int e) {
82 | Fp2Point pAp = p;
83 | for (int i = 0; i < e; i++) {
84 | pAp = xDbl(curve, pAp);
85 | }
86 | return pAp;
87 | }
88 |
89 | @Override
90 | public Fp2Point xTple(MontgomeryCurve curve, Fp2Point p, int e) {
91 | Fp2Point pAp = p;
92 | for (int i = 0; i < e; i++) {
93 | pAp = xTpl(curve, pAp);
94 | }
95 | return pAp;
96 | }
97 |
98 | @Override
99 | public Fp2Element jInv(MontgomeryCurve curve) {
100 | Fp2Element t0, t1, j;
101 | Fp2Element a = curve.getA();
102 | SikeParam sikeParam = curve.getSikeParam();
103 | t0 = a.square();
104 | j = sikeParam.getFp2ElementFactory().generate(new BigInteger("3"));
105 | j = t0.subtract(j);
106 | t1 = j.square();
107 | j = j.multiply(t1);
108 | j = j.add(j);
109 | j = j.add(j);
110 | j = j.add(j);
111 | j = j.add(j);
112 | j = j.add(j);
113 | j = j.add(j);
114 | j = j.add(j);
115 | j = j.add(j);
116 | t1 = sikeParam.getFp2ElementFactory().generate(new BigInteger("4"));
117 | t0 = t0.subtract(t1);
118 | t0 = t0.inverse();
119 | j = j.multiply(t0);
120 | return j;
121 | }
122 |
123 | @Override
124 | public Fp2Element getA(SikeParam sikeParam, Fp2Element px, Fp2Element qx, Fp2Element rx) {
125 | Fp2Element t0, t1, a;
126 | t1 = px.add(qx);
127 | t0 = px.multiply(qx);
128 | a = rx.multiply(t1);
129 | a = a.add(t0);
130 | t0 = t0.multiply(rx);
131 | a = a.subtract(sikeParam.getFp2ElementFactory().one());
132 | t0 = t0.add(t0);
133 | t1 = t1.add(rx);
134 | t0 = t0.add(t0);
135 | a = a.square();
136 | t0 = t0.inverse();
137 | a = a.multiply(t0);
138 | a = a.subtract(t1);
139 | return a;
140 | }
141 |
142 | /**
143 | * Double-and-add scalar multiplication.
144 | * @param curve Current curve.
145 | * @param m Scalar value.
146 | * @param p Point on the curve.
147 | * @param bits Number of bits in field elements.
148 | * @return Calculated new point.
149 | */
150 | public Fp2Point doubleAndAdd(MontgomeryCurve curve, BigInteger m, Fp2Point p, int bits) {
151 | SikeParam sikeParam = curve.getSikeParam();
152 | Fp2Point q = Fp2PointAffine.infinity(sikeParam);
153 | for (int i = bits - 1; i >= 0; i--) {
154 | q = xDbl(curve, q);
155 | if (m.testBit(i)) {
156 | q = xAdd(curve, q, p);
157 | }
158 | }
159 | return q;
160 | }
161 |
162 | /**
163 | * Adding of two points.
164 | * @param curve Current curve.
165 | * @param p First point on the curve.
166 | * @param q Second point on the curve.
167 | * @return Calculated new point.
168 | */
169 | public Fp2Point xAdd(MontgomeryCurve curve, Fp2Point p, Fp2Point q) {
170 | if (p.isInfinite()) {
171 | return q;
172 | }
173 | if (q.isInfinite()) {
174 | return p;
175 | }
176 | if (p.equals(q)) {
177 | return xDbl(curve, p);
178 | }
179 | if (p.equals(q.negate())) {
180 | SikeParam sikeParam = curve.getSikeParam();
181 | return Fp2PointAffine.infinity(sikeParam);
182 | }
183 |
184 | Fp2Element t0, t1, t2, xpq, ypq;
185 | Fp2Element b = curve.getB();
186 |
187 | t0 = q.getY().subtract(p.getY());
188 | t1 = q.getX().subtract(p.getX());
189 | t1 = t1.inverse();
190 | t0 = t0.multiply(t1);
191 | t1 = t0.square();
192 | t2 = p.getX().add(p.getX());
193 | t2 = t2.add(q.getX());
194 | t2 = t2.add(curve.getA());
195 | t2 = t2.multiply(t0);
196 | t0 = t0.multiply(t1);
197 | t0 = b.multiply(t0);
198 | t0 = t0.add(p.getY());
199 | t0 = t2.subtract(t0);
200 | t1 = b.multiply(t1);
201 | t1 = t1.subtract(curve.getA());
202 | t1 = t1.subtract(p.getX());
203 | xpq = t1.subtract(q.getX());
204 | ypq = t0;
205 | return new Fp2PointAffine(xpq, ypq);
206 | }
207 |
208 | /**
209 | * Recover the point R = P - Q.
210 | * @param curve Current curve.
211 | * @param p Point P.
212 | * @param q Point Q.
213 | * @return Calculated point R.
214 | */
215 | public Fp2Point getXr(MontgomeryCurve curve, Fp2Point p, Fp2Point q) {
216 | Fp2Point qNeg = new Fp2PointAffine(q.getX(), q.getY().negate());
217 | return xAdd(curve, p, qNeg);
218 | }
219 |
220 | /**
221 | * Recover the curve and points P and Q.
222 | * @param sikeParam SIKE parameters.
223 | * @param px The x coordinate of point P.
224 | * @param qx The x coordinate of point Q.
225 | * @param rx The x coordinate of point R.
226 | * @return A recovered curve and points P and Q.
227 | */
228 | public EvaluatedCurve getYpYqAB(SikeParam sikeParam, Fp2Element px, Fp2Element qx, Fp2Element rx) {
229 | Fp2Element b, t1, t2, py, qy;
230 | Fp2Element a = getA(sikeParam, px, qx, rx);
231 | b = sikeParam.getFp2ElementFactory().one();
232 | MontgomeryCurve curve = new MontgomeryCurve(sikeParam, a, b);
233 | t1 = px.square();
234 | t2 = px.multiply(t1);
235 | t1 = a.multiply(t1);
236 | t1 = t2.add(t1);
237 | t1 = t1.add(px);
238 | py = t1.sqrt();
239 | t1 = qx.square();
240 | t2 = qx.multiply(t1);
241 | t1 = a.multiply(t1);
242 | t1 = t2.add(t1);
243 | t1 = t1.add(qx);
244 | qy = t1.sqrt();
245 | Fp2Point p = new Fp2PointAffine(px, py);
246 | Fp2Point q1 = new Fp2PointAffine(qx, qy.negate());
247 | Fp2Point t = xAdd(curve, p, q1);
248 | if (!t.getX().equals(rx)) {
249 | qy = qy.negate();
250 | }
251 | Fp2Point q = new Fp2PointAffine(qx, qy);
252 | return new EvaluatedCurve(curve, p, q);
253 | }
254 |
255 | }
256 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/reference/fp/Fp2ElementFactoryRef.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.reference.fp;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.math.api.Fp2ElementFactory;
21 | import com.wultra.security.pqc.sike.param.SikeParam;
22 |
23 | import java.math.BigInteger;
24 |
25 | /**
26 | * Factory for reference elements of quadratic extension field F(p^2).
27 | *
28 | * @author Roman Strobl, roman.strobl@wultra.com
29 | */
30 | public class Fp2ElementFactoryRef implements Fp2ElementFactory {
31 |
32 | private final SikeParam sikeParam;
33 |
34 | /**
35 | * Fp2Element factory constructor for reference elements.
36 | * @param sikeParam SIKE parameters.
37 | */
38 | public Fp2ElementFactoryRef(SikeParam sikeParam) {
39 | this.sikeParam = sikeParam;
40 | }
41 |
42 | @Override
43 | public Fp2Element zero() {
44 | return new Fp2ElementRef(sikeParam, BigInteger.ZERO, BigInteger.ZERO);
45 | }
46 |
47 | @Override
48 | public Fp2Element one() {
49 | return new Fp2ElementRef(sikeParam, BigInteger.ONE, BigInteger.ZERO);
50 | }
51 |
52 | @Override
53 | public Fp2Element generate(BigInteger x0r) {
54 | return new Fp2ElementRef(sikeParam, x0r, BigInteger.ZERO);
55 | }
56 |
57 | @Override
58 | public Fp2Element generate(BigInteger x0r, BigInteger x0i) {
59 | return new Fp2ElementRef(sikeParam, x0r, x0i);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/reference/fp/Fp2ElementRef.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.reference.fp;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.math.api.FpElement;
21 | import com.wultra.security.pqc.sike.param.SikeParam;
22 |
23 | import java.math.BigInteger;
24 | import java.util.Objects;
25 |
26 | /**
27 | * Element of a quadratic extension field F(p^2): x0 + x1*i.
28 | *
29 | * @author Roman Strobl, roman.strobl@wultra.com
30 | */
31 | public class Fp2ElementRef implements Fp2Element {
32 |
33 | private final FpElement x0;
34 | private final FpElement x1;
35 |
36 | private final SikeParam sikeParam;
37 |
38 | /**
39 | * The F(p^2) field element constructor for given F(p) elements.
40 | * @param sikeParam SIKE parameters.
41 | * @param x0 The x0 real F(p) element.
42 | * @param x1 The x1 imaginary F(p) element.
43 | */
44 | public Fp2ElementRef(SikeParam sikeParam, FpElement x0, FpElement x1) {
45 | this.sikeParam = sikeParam;
46 | this.x0 = x0.copy();
47 | this.x1 = x1.copy();
48 | }
49 |
50 | /**
51 | * The F(p^2) field element constructor for given BigInteger values.
52 | * @param sikeParam SIKE parameters.
53 | * @param x0b The x0 real F(p) element.
54 | * @param x1b The x1 imaginary F(p) element.
55 | */
56 | public Fp2ElementRef(SikeParam sikeParam, BigInteger x0b, BigInteger x1b) {
57 | this.sikeParam = sikeParam;
58 | this.x0 = new FpElementRef(sikeParam, x0b);
59 | this.x1 = new FpElementRef(sikeParam, x1b);
60 | }
61 |
62 | /**
63 | * Get the real part of element.
64 | * @return Real part of element.
65 | */
66 | public FpElement getX0() {
67 | return x0;
68 | }
69 |
70 | /**
71 | * Get the imaginary part of element.
72 | * @return Imaginary part of element.
73 | */
74 | public FpElement getX1() {
75 | return x1;
76 | }
77 |
78 | /**
79 | * Add two elements.
80 | * @param y Other element.
81 | * @return Calculation result.
82 | */
83 | public Fp2Element add(Fp2Element y) {
84 | // y = (x0 + i*x1) + (y0 + i*y1) = x0 + y0 + i*(x1 + y1)
85 | FpElement r, i;
86 |
87 | r = x0.add(y.getX0());
88 | i = x1.add(y.getX1());
89 | return new Fp2ElementRef(sikeParam, r, i);
90 | }
91 |
92 | /**
93 | * Subtract two elements.
94 | * @param y Other element.
95 | * @return Calculation result.
96 | */
97 | public Fp2Element subtract(Fp2Element y) {
98 | // y = (x0 + i*x1) - (y0 + i*y1) = x0 - y0 + i*(x1 - y1)
99 | FpElement r, i;
100 |
101 | r = x0.subtract(y.getX0());
102 | i = x1.subtract(y.getX1());
103 | return new Fp2ElementRef(sikeParam, r, i);
104 | }
105 |
106 | /**
107 | * Multiply two elements.
108 | * @param y Other element.
109 | * @return Calculation result.
110 | */
111 | public Fp2Element multiply(Fp2Element y) {
112 | // y = (x0 + i*x1) * (y0 + i*y1) = x0y0 - x1y1 + i*(x0y1 + x1y0)
113 | FpElement r1, r2, r, i1, i2, i;
114 |
115 | r1 = x0.multiply(y.getX0());
116 | r2 = x1.multiply(y.getX1());
117 | r = r1.subtract(r2);
118 |
119 | i1 = x0.multiply(y.getX1());
120 | i2 = x1.multiply(y.getX0());
121 | i = i1.add(i2);
122 |
123 | return new Fp2ElementRef(sikeParam, r, i);
124 | }
125 |
126 | /**
127 | * Multiply by the imaginary part of the element.
128 | * @return Calculation result.
129 | */
130 | public Fp2Element multiplyByI() {
131 | return new Fp2ElementRef(sikeParam, x1.negate(), x0.copy());
132 | }
133 |
134 | /**
135 | * Square the element.
136 | * @return Calculation result.
137 | */
138 | public Fp2Element square() {
139 | return multiply(this);
140 | }
141 |
142 | /**
143 | * Element exponentiation.
144 | * @param n Exponent
145 | * @return Calculation result.
146 | */
147 | public Fp2Element pow(BigInteger n) {
148 | if (n.compareTo(BigInteger.ZERO) < 0) {
149 | throw new ArithmeticException("Negative exponent");
150 | }
151 | if (n.compareTo(BigInteger.ZERO) == 0) {
152 | return sikeParam.getFp2ElementFactory().one();
153 | }
154 | if (n.compareTo(BigInteger.ONE) == 0) {
155 | return copy();
156 | }
157 | BigInteger e = n;
158 | Fp2Element base = copy();
159 | Fp2Element result = sikeParam.getFp2ElementFactory().one();
160 | while (e.compareTo(BigInteger.ZERO) > 0) {
161 | if (e.testBit(0)) {
162 | result = result.multiply(base);
163 | }
164 | e = e.shiftRight(1);
165 | base = base.square();
166 | }
167 | return result;
168 | }
169 |
170 | /**
171 | * Calculate the square root of the element.
172 | * @return Calculation result.
173 | */
174 | public Fp2Element sqrt() {
175 | // TODO - compare performance with reference C implementation, consider replacing algorithm
176 | if (isZero()) {
177 | return sikeParam.getFp2ElementFactory().zero();
178 | }
179 | if (!isQuadraticResidue()) {
180 | throw new ArithmeticException("The square root of a quadratic non-residue cannot be computed");
181 | }
182 | BigInteger prime = sikeParam.getPrime();
183 | if (prime.mod(new BigInteger("4")).compareTo(new BigInteger("3")) != 0) {
184 | throw new ArithmeticException("Field prime mod 4 is not 3");
185 | }
186 | Fp2Element a1, a2;
187 | Fp2Element neg1 = sikeParam.getFp2ElementFactory().one();
188 | BigInteger p = prime;
189 | p = p.shiftRight(2);
190 | a1 = copy();
191 | a1 = a1.pow(p);
192 | a2 = copy();
193 | a2 = a2.multiply(a1);
194 | a1 = a1.multiply(a2);
195 | if (a1.equals(neg1)) {
196 | return a2.multiplyByI();
197 | }
198 | p = prime;
199 | p = p.shiftRight(1);
200 | a1 = a1.add(sikeParam.getFp2ElementFactory().one());
201 | a1 = a1.pow(p);
202 | return a1.multiply(a2);
203 | }
204 |
205 | /**
206 | * Get whether the element is a quadratic residue modulo prime.
207 | * @return Whether the element is a quadratic residue.
208 | */
209 | public boolean isQuadraticResidue() {
210 | Fp2Element base = copy();
211 | BigInteger p = sikeParam.getPrime();
212 | p = p.multiply(p);
213 | p = p.subtract(BigInteger.ONE);
214 | p = p.shiftRight(1);
215 | base = base.pow(p);
216 | return base.equals(sikeParam.getFp2ElementFactory().one());
217 | }
218 |
219 | /**
220 | * Invert the element.
221 | * @return Calculation result.
222 | */
223 | public Fp2ElementRef inverse() {
224 | FpElement t0, t1, o0, o1;
225 | t0 = x0.square();
226 | t1 = x1.square();
227 | t0 = t0.add(t1);
228 | t0 = t0.inverse();
229 | o1 = x1.negate();
230 | o0 = x0.multiply(t0);
231 | o1 = o1.multiply(t0);
232 | return new Fp2ElementRef(sikeParam, o0, o1);
233 | }
234 |
235 | /**
236 | * Negate the element.
237 | * @return Calculation result.
238 | */
239 | public Fp2Element negate() {
240 | return new Fp2ElementRef(sikeParam, x0.negate(), x1.negate());
241 | }
242 |
243 | /**
244 | * Get whether the element is the zero element.
245 | * @return Whether the element is the zero element.
246 | */
247 | public boolean isZero() {
248 | return x0.isZero() && x1.isZero();
249 | }
250 |
251 | /**
252 | * Copy the element.
253 | * @return Element copy.
254 | */
255 | public Fp2Element copy() {
256 | return new Fp2ElementRef(sikeParam, new FpElementRef(sikeParam, x0.getX()), new FpElementRef(sikeParam, x1.getX()));
257 | }
258 |
259 | /**
260 | * Encode the element in bytes.
261 | * @return Encoded element in bytes.
262 | */
263 | public byte[] getEncoded() {
264 | byte[] x0Encoded = x0.getEncoded();
265 | byte[] x1Encoded = x1.getEncoded();
266 | byte[] encoded = new byte[x0Encoded.length + x1Encoded.length];
267 | System.arraycopy(x0Encoded, 0, encoded, 0, x0Encoded.length);
268 | System.arraycopy(x1Encoded, 0, encoded, x0Encoded.length, x1Encoded.length);
269 | return encoded;
270 | }
271 |
272 | /**
273 | * Convert element to octet string.
274 | * @return Octet string.
275 | */
276 | public String toOctetString() {
277 | return x0.toOctetString() + x1.toOctetString();
278 | }
279 |
280 | @Override
281 | public String toString() {
282 | return x1 + "i" + " + " + x0;
283 | }
284 |
285 | @Override
286 | public boolean equals(Object o) {
287 | if (this == o) return true;
288 | if (o == null || getClass() != o.getClass()) return false;
289 | Fp2ElementRef that = (Fp2ElementRef) o;
290 | return sikeParam.getPrime().equals(that.sikeParam.getPrime())
291 | && x0.equals(that.x0)
292 | && x1.equals(that.x1);
293 | }
294 |
295 | @Override
296 | public int hashCode() {
297 | return Objects.hash(sikeParam, x0, x1);
298 | }
299 | }
300 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/math/reference/fp/FpElementRef.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math.reference.fp;
18 |
19 | import com.wultra.security.pqc.sike.math.api.FpElement;
20 | import com.wultra.security.pqc.sike.param.SikeParam;
21 | import com.wultra.security.pqc.sike.util.ByteEncoding;
22 | import com.wultra.security.pqc.sike.util.OctetEncoding;
23 |
24 | import java.math.BigInteger;
25 | import java.util.Objects;
26 |
27 | /**
28 | * Element of an F(p) field with a single coordinate x.
29 | *
30 | * @author Roman Strobl, roman.strobl@wultra.com
31 | */
32 | public class FpElementRef implements FpElement {
33 |
34 | private final BigInteger x;
35 |
36 | private final SikeParam sikeParam;
37 |
38 | /**
39 | * The F(p^) field element constructor for given BigInteger value.
40 | * @param sikeParam Field prime.
41 | * @param x BigInteger value.
42 | */
43 | public FpElementRef(SikeParam sikeParam, BigInteger x) {
44 | this.sikeParam = sikeParam;
45 | this.x = x.mod(sikeParam.getPrime());
46 | }
47 |
48 | /**
49 | * Get the element value.
50 | * @return the element value.
51 | */
52 | public BigInteger getX() {
53 | return x;
54 | }
55 |
56 | /**
57 | * Get the field prime.
58 | * @return Field prime.
59 | */
60 | public BigInteger getPrime() {
61 | return sikeParam.getPrime();
62 | }
63 |
64 | /**
65 | * Add two elements.
66 | * @param o Other element.
67 | * @return Calculation result.
68 | */
69 | public FpElement add(FpElement o) {
70 | return new FpElementRef(sikeParam, x.add(o.getX()).mod(getPrime()));
71 | }
72 |
73 | /**
74 | * Subtract two elements.
75 | * @param o Other element.
76 | * @return Calculation result.
77 | */
78 | public FpElement subtract(FpElement o) {
79 | return new FpElementRef(sikeParam, x.subtract(o.getX()).mod(getPrime()));
80 | }
81 |
82 | /**
83 | * Multiply two elements.
84 | * @param o Other element.
85 | * @return Calculation result.
86 | */
87 | public FpElement multiply(FpElement o) {
88 | return new FpElementRef(sikeParam, x.multiply(o.getX()).mod(getPrime()));
89 | }
90 |
91 | /**
92 | * Square the elements.
93 | * @return Calculation result.
94 | */
95 | public FpElement square() {
96 | return multiply(this);
97 | }
98 |
99 | /**
100 | * Invert the element.
101 | * @return Calculation result.
102 | */
103 | public FpElement inverse() {
104 | return new FpElementRef(sikeParam, x.modInverse(getPrime()));
105 | }
106 |
107 | /**
108 | * Negate the element.
109 | * @return Calculation result.
110 | */
111 | public FpElement negate() {
112 | return new FpElementRef(sikeParam, getPrime().subtract(x));
113 | }
114 |
115 | /**
116 | * Get whether the element is the zero element.
117 | * @return Whether the element is the zero element.
118 | */
119 | public boolean isZero() {
120 | return BigInteger.ZERO.equals(x);
121 | }
122 |
123 | /**
124 | * Copy the element.
125 | * @return Element copy.
126 | */
127 | public FpElement copy() {
128 | return new FpElementRef(sikeParam, x);
129 | }
130 |
131 | /**
132 | * Encode the element in bytes.
133 | * @return Encoded element in bytes.
134 | */
135 | public byte[] getEncoded() {
136 | int primeSize = (sikeParam.getPrime().bitLength() + 7) / 8;
137 | return ByteEncoding.toByteArray(x, primeSize);
138 | }
139 |
140 | /**
141 | * Convert element to octet string.
142 | * @return Octet string.
143 | */
144 | public String toOctetString() {
145 | int primeSize = (sikeParam.getPrime().bitLength() + 7) / 8;
146 | return OctetEncoding.toOctetString(x, primeSize);
147 | }
148 |
149 | @Override
150 | public String toString() {
151 | return x.toString();
152 | }
153 |
154 | @Override
155 | public boolean equals(Object o) {
156 | if (this == o) return true;
157 | if (o == null || getClass() != o.getClass()) return false;
158 | FpElementRef fpElement = (FpElementRef) o;
159 | return getPrime().equals(fpElement.getPrime())
160 | && x.equals(fpElement.x);
161 | }
162 |
163 | @Override
164 | public int hashCode() {
165 | return Objects.hash(getPrime(), x);
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/model/EncapsulationResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.model;
18 |
19 | import com.wultra.security.pqc.sike.util.SideChannelUtil;
20 |
21 | import java.util.Arrays;
22 | import java.util.Objects;
23 |
24 | /**
25 | * SIKE encapsulation result.
26 | *
27 | * @author Roman Strobl, roman.strobl@wultra.com
28 | */
29 | public class EncapsulationResult {
30 |
31 | private final byte[] secret;
32 | private final EncryptedMessage encryptedMessage;
33 |
34 | /**
35 | * SIKE encapsulation result constructor.
36 | * @param secret Shared secret.
37 | * @param encryptedMessage Encrypted message to be sent to Bob.
38 | */
39 | public EncapsulationResult(byte[] secret, EncryptedMessage encryptedMessage) {
40 | this.secret = secret;
41 | this.encryptedMessage = encryptedMessage;
42 | }
43 |
44 | /**
45 | * Get the shared secret.
46 | * @return Shared secret.
47 | */
48 | public byte[] getSecret() {
49 | return secret;
50 | }
51 |
52 | /**
53 | * Get the encrypted message.
54 | * @return Encypted message.
55 | */
56 | public EncryptedMessage getEncryptedMessage() {
57 | return encryptedMessage;
58 | }
59 |
60 | @Override
61 | public boolean equals(Object o) {
62 | if (this == o) return true;
63 | if (o == null || getClass() != o.getClass()) return false;
64 | EncapsulationResult that = (EncapsulationResult) o;
65 | // Use constant time comparison to avoid timing attacks
66 | return SideChannelUtil.constantTimeAreEqual(secret, that.secret) &
67 | encryptedMessage.equals(that.encryptedMessage);
68 | }
69 |
70 | @Override
71 | public int hashCode() {
72 | return Objects.hash(encryptedMessage, Arrays.hashCode(secret));
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/model/EncryptedMessage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.model;
18 |
19 | import com.wultra.security.pqc.sike.param.SikeParam;
20 | import com.wultra.security.pqc.sike.util.SideChannelUtil;
21 |
22 | import java.security.InvalidParameterException;
23 | import java.security.PublicKey;
24 | import java.util.Arrays;
25 | import java.util.Objects;
26 |
27 | /**
28 | * SIKE encrypted message.
29 | *
30 | * @author Roman Strobl, roman.strobl@wultra.com
31 | */
32 | public class EncryptedMessage {
33 |
34 | private final PublicKey c0;
35 | private final byte[] c1;
36 |
37 | /**
38 | * SIKE encrypted message constructor from public key and encrypted data.
39 | * @param c0 Alice's public key.
40 | * @param c1 Encrypted data.
41 | */
42 | public EncryptedMessage(PublicKey c0, byte[] c1) {
43 | this.c0 = c0;
44 | this.c1 = c1;
45 | }
46 |
47 | /**
48 | * SIKE encrypted message constructor from message encoded into byte array.
49 | * @param sikeParam SIKE parameters.
50 | * @param bytes Encrypted message encoded into byte array.
51 | */
52 | public EncryptedMessage(SikeParam sikeParam, byte[] bytes) {
53 | if (sikeParam == null) {
54 | throw new InvalidParameterException("Invalid parameter sikeParam");
55 | }
56 | int primeSize = (sikeParam.getPrime().bitLength() + 7) / 8;
57 | int pubKeySize = primeSize * 6;
58 | int messageSize = sikeParam.getMessageBytes();
59 | int expectedSize = pubKeySize + messageSize;
60 | if (bytes == null || bytes.length != expectedSize) {
61 | throw new InvalidParameterException("Invalid parameter bytes");
62 | }
63 | byte[] pubKeyBytes = new byte[pubKeySize];
64 | System.arraycopy(bytes, 0, pubKeyBytes, 0, pubKeySize);
65 | this.c0 = new SidhPublicKey(sikeParam, pubKeyBytes);
66 | this.c1 = new byte[messageSize];
67 | System.arraycopy(bytes, pubKeySize, this.c1, 0, messageSize);
68 | }
69 |
70 | /**
71 | * Get encrypted message encoded into byte array.
72 | * @return Encrypted message encoded into byte array.
73 | */
74 | public byte[] getEncoded() {
75 | if (c0 == null || c1 == null) {
76 | return null;
77 | }
78 | byte[] pubKey = c0.getEncoded();
79 | byte[] encoded = new byte[pubKey.length + c1.length];
80 | System.arraycopy(pubKey, 0, encoded, 0, pubKey.length);
81 | System.arraycopy(c1, 0, encoded, pubKey.length, c1.length);
82 | return encoded;
83 | }
84 |
85 | /**
86 | * Get Alice's public key.
87 | * @return Public key.
88 | */
89 | public PublicKey getC0() {
90 | return c0;
91 | }
92 |
93 | /**
94 | * Get encrypted data.
95 | * @return Encrypted data.
96 | */
97 | public byte[] getC1() {
98 | return c1;
99 | }
100 |
101 | @Override
102 | public boolean equals(Object o) {
103 | if (this == o) return true;
104 | if (o == null || getClass() != o.getClass()) return false;
105 | EncryptedMessage that = (EncryptedMessage) o;
106 | // Use constant time comparison to avoid timing attacks
107 | return SideChannelUtil.constantTimeAreEqual(getEncoded(), that.getEncoded());
108 | }
109 |
110 | @Override
111 | public int hashCode() {
112 | return Objects.hash(c0, Arrays.hashCode(c1));
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/model/EvaluatedCurve.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.model;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Point;
20 |
21 | import java.util.Objects;
22 |
23 | /**
24 | * Evaluated curve and optional points.
25 | *
26 | * @author Roman Strobl, roman.strobl@wultra.com
27 | */
28 | public class EvaluatedCurve {
29 |
30 | private final MontgomeryCurve curve;
31 | private final Fp2Point p;
32 | private final Fp2Point q;
33 | private final Fp2Point r;
34 |
35 | /**
36 | * Curve constructor.
37 | * @param curve Evaluated curve.
38 | * @param p Optional point P.
39 | * @param q Optional point Q.
40 | */
41 | public EvaluatedCurve(MontgomeryCurve curve, Fp2Point p, Fp2Point q) {
42 | this.curve = curve;
43 | this.p = p;
44 | this.q = q;
45 | this.r = null;
46 | }
47 |
48 | /**
49 | * Curve constructor.
50 | * @param curve Evaluated curve.
51 | * @param p Optional point P.
52 | * @param q Optional point Q.
53 | * @param r Optional point R.
54 | */
55 | public EvaluatedCurve(MontgomeryCurve curve, Fp2Point p, Fp2Point q, Fp2Point r) {
56 | this.curve = curve;
57 | this.p = p;
58 | this.q = q;
59 | this.r = r;
60 | }
61 |
62 | /**
63 | * Get the evaluated curve.
64 | * @return Evaluated curve.
65 | */
66 | public MontgomeryCurve getCurve() {
67 | return curve;
68 | }
69 |
70 | /**
71 | * Get optional point P.
72 | * @return Optional point P.
73 | */
74 | public Fp2Point getP() {
75 | return p;
76 | }
77 |
78 | /**
79 | * Get optional point Q.
80 | * @return Optional point Q.
81 | */
82 | public Fp2Point getQ() {
83 | return q;
84 | }
85 |
86 | /**
87 | * Get optional point R.
88 | * @return Optional point R.
89 | */
90 | public Fp2Point getR() {
91 | return r;
92 | }
93 |
94 | @Override
95 | public String toString() {
96 | return curve.toString();
97 | }
98 |
99 | @Override
100 | public boolean equals(Object o) {
101 | if (this == o) return true;
102 | if (o == null || getClass() != o.getClass()) return false;
103 | EvaluatedCurve that = (EvaluatedCurve) o;
104 | // Use & to avoid timing attacks
105 | return curve.equals(that.curve)
106 | & Objects.equals(p, that.p)
107 | & Objects.equals(q, that.q)
108 | & Objects.equals(r, that.r);
109 | }
110 |
111 | @Override
112 | public int hashCode() {
113 | return Objects.hash(curve, p, q, r);
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/model/ImplementationType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.model;
18 |
19 | /**
20 | * SIKE implementation type.
21 | *
22 | * @author Roman Strobl, roman.strobl@wultra.com
23 | */
24 | public enum ImplementationType {
25 | REFERENCE,
26 | OPTIMIZED
27 | }
28 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/model/MontgomeryCurve.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.model;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.model.optimized.MontgomeryConstants;
21 | import com.wultra.security.pqc.sike.param.SikeParam;
22 |
23 | import java.security.InvalidParameterException;
24 | import java.util.Objects;
25 |
26 | /**
27 | * Montgomery curve parameters.
28 | *
29 | * @author Roman Strobl, roman.strobl@wultra.com
30 | */
31 | public class MontgomeryCurve {
32 |
33 | private final SikeParam sikeParam;
34 | private Fp2Element a;
35 | private Fp2Element b;
36 | private MontgomeryConstants optimizedConstants;
37 |
38 | /**
39 | * Montgomery curve constructor.
40 | * @param sikeParam SIKE parameters.
41 | */
42 | public MontgomeryCurve(SikeParam sikeParam) {
43 | this.sikeParam = sikeParam;
44 | if (sikeParam.getImplementationType() == ImplementationType.OPTIMIZED) {
45 | optimizedConstants = new MontgomeryConstants(sikeParam);
46 | }
47 | }
48 |
49 | /**
50 | * Montgomery curve constructor.
51 | * @param sikeParam SIKE parameters.
52 | * @param a Montgomery curve coefficient a.
53 | */
54 | public MontgomeryCurve(SikeParam sikeParam, Fp2Element a) {
55 | this.sikeParam = sikeParam;
56 | this.a = a;
57 | if (sikeParam.getImplementationType() == ImplementationType.OPTIMIZED) {
58 | optimizedConstants = new MontgomeryConstants(sikeParam, a);
59 | }
60 | }
61 |
62 | /**
63 | * Montgomery curve constructor.
64 | * @param sikeParam SIKE parameters.
65 | * @param a Montgomery curve coefficient a.
66 | * @param b Montgomery curve coefficient b.
67 | */
68 | public MontgomeryCurve(SikeParam sikeParam, Fp2Element a, Fp2Element b) {
69 | this(sikeParam, a);
70 | this.b = b;
71 | }
72 |
73 | /**
74 | * Get SIKE parameters.
75 | * @return SIKE parameters.
76 | */
77 | public SikeParam getSikeParam() {
78 | return sikeParam;
79 | }
80 |
81 | /**
82 | * Get Montgomery curve coefficient a.
83 | * @return Montgomery curve coefficient a.
84 | */
85 | public Fp2Element getA() {
86 | return a;
87 | }
88 |
89 | /**
90 | * Set Montgomery curve coefficient a.
91 | * @param a Montgomery curve coefficient a.
92 | */
93 | public void setA(Fp2Element a) {
94 | this.a = a;
95 | }
96 |
97 | /**
98 | * Get Montgomery curve coefficient b.
99 | * @return Montgomery curve coefficient b.
100 | */
101 | public Fp2Element getB() {
102 | return b;
103 | }
104 |
105 | /**
106 | * Set Montgomery curve coefficient b.
107 | * @param b Montgomery curve coefficient b.
108 | */
109 | public void setB(Fp2Element b) {
110 | this.b = b;
111 | }
112 |
113 | /**
114 | * Get optimized montgomery constants for this curve.
115 | * @return Optimized montgomery constants for this curve.
116 | */
117 | public MontgomeryConstants getOptimizedConstants() {
118 | if (sikeParam.getImplementationType() != ImplementationType.OPTIMIZED) {
119 | throw new InvalidParameterException("Invalid implementation type");
120 | }
121 | return optimizedConstants;
122 | }
123 |
124 | @Override
125 | public String toString() {
126 | if (sikeParam.getImplementationType() == ImplementationType.OPTIMIZED) {
127 | return "a = " + a + ", " + optimizedConstants;
128 | }
129 | return "a = " + a + ", b = " + b;
130 | }
131 |
132 | @Override
133 | public boolean equals(Object o) {
134 | if (this == o) return true;
135 | if (o == null || getClass() != o.getClass()) return false;
136 | MontgomeryCurve that = (MontgomeryCurve) o;
137 | return sikeParam.equals(that.sikeParam) &&
138 | a.equals(that.a) &&
139 | Objects.equals(b, that.b) &&
140 | Objects.equals(optimizedConstants, that.optimizedConstants);
141 | }
142 |
143 | @Override
144 | public int hashCode() {
145 | return Objects.hash(sikeParam, a, b, optimizedConstants);
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/model/Party.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.model;
18 |
19 | /**
20 | * A party involved in SIDH or SIKE communication.
21 | *
22 | * In case of SIKE, Bob is the client and Alice is the server.
23 | *
24 | * @author Roman Strobl, roman.strobl@wultra.com
25 | */
26 | public enum Party {
27 | ALICE,
28 | BOB
29 | }
30 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/model/SidhPrivateKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.model;
18 |
19 | import com.wultra.security.pqc.sike.math.api.FpElement;
20 | import com.wultra.security.pqc.sike.param.SikeParam;
21 | import com.wultra.security.pqc.sike.util.ByteEncoding;
22 | import com.wultra.security.pqc.sike.util.OctetEncoding;
23 | import com.wultra.security.pqc.sike.util.SideChannelUtil;
24 |
25 | import java.math.BigInteger;
26 | import java.nio.charset.StandardCharsets;
27 | import java.security.InvalidParameterException;
28 | import java.security.PrivateKey;
29 | import java.util.Arrays;
30 | import java.util.Objects;
31 |
32 | /**
33 | * SIDH or SIKE private key.
34 | *
35 | * @author Roman Strobl, roman.strobl@wultra.com
36 | */
37 | public class SidhPrivateKey implements PrivateKey {
38 |
39 | private final SikeParam sikeParam;
40 | private final Party party;
41 | private final byte[] key;
42 | private final byte[] s;
43 |
44 | /**
45 | * Construct private key from a number.
46 | * @param sikeParam SIKE parameters.
47 | * @param party Alice or Bob.
48 | * @param secret Secret value of the private key.
49 | */
50 | public SidhPrivateKey(SikeParam sikeParam, Party party, BigInteger secret) {
51 | this.sikeParam = sikeParam;
52 | this.party = party;
53 | validatePrivateKey(secret);
54 | int keyLength = (sikeParam.getPrime().bitLength() + 7) / 8;
55 | this.key = ByteEncoding.toByteArray(secret, keyLength);
56 | this.s = new byte[sikeParam.getMessageBytes()];
57 | }
58 |
59 | /**
60 | * Construct private key from bytes.
61 | * @param sikeParam SIKE parameters.
62 | * @param party Alice or Bob.
63 | * @param bytes Byte value of the private key.
64 | */
65 | public SidhPrivateKey(SikeParam sikeParam, Party party, byte[] bytes) {
66 | this.sikeParam = sikeParam;
67 | this.party = party;
68 | int sLength = sikeParam.getMessageBytes();
69 | int keyLength = (sikeParam.getPrime().bitLength() + 7) / 8;
70 | if (bytes == null || bytes.length != sLength + keyLength) {
71 | throw new InvalidParameterException("Invalid private key");
72 | }
73 | byte[] s = new byte[sLength];
74 | key = new byte[keyLength];
75 | System.arraycopy(bytes, 0, s, 0, sLength);
76 | System.arraycopy(bytes, sLength, key, 0, keyLength);
77 | BigInteger secret = ByteEncoding.fromByteArray(key);
78 | validatePrivateKey(secret);
79 | this.s = s;
80 | }
81 |
82 | /**
83 | * Construct private key from octets.
84 | * @param sikeParam SIKE parameters.
85 | * @param party Alice or Bob.
86 | * @param octets Octet value of the private key.
87 | */
88 | public SidhPrivateKey(SikeParam sikeParam, Party party, String octets) {
89 | this.sikeParam = sikeParam;
90 | this.party = party;
91 | int sLength = sikeParam.getMessageBytes();
92 | int keyLength = getKeyLength(party);
93 | if (octets == null || octets.length() != (sLength + keyLength) * 2) {
94 | throw new InvalidParameterException("Invalid private key");
95 | }
96 | byte[] bytes = octets.getBytes(StandardCharsets.UTF_8);
97 | byte[] s = new byte[sLength * 2];
98 | byte[] key = new byte[keyLength * 2];
99 | System.arraycopy(bytes, 0, s, 0, sLength * 2);
100 | System.arraycopy(bytes, sLength * 2, key, 0, keyLength * 2);
101 | BigInteger sVal = OctetEncoding.fromOctetString(new String(s));
102 | BigInteger secret = OctetEncoding.fromOctetString(new String(key));
103 | validatePrivateKey(secret);
104 | this.s = ByteEncoding.toByteArray(sVal, sLength);
105 | int primeSize = (sikeParam.getPrime().bitLength() + 7) / 8;
106 | this.key = ByteEncoding.toByteArray(secret, primeSize);
107 | }
108 |
109 | /**
110 | * Construct private key from bytes with specified parameter s for SIKE decapsulation.
111 | * @param sikeParam SIKE parameters.
112 | * @param party Alice or Bob.
113 | * @param key Byte value of the private key.
114 | * @param s Parameter s for SIKE decapsulation.
115 | */
116 | public SidhPrivateKey(SikeParam sikeParam, Party party, BigInteger key, byte[] s) {
117 | this(sikeParam, party, key);
118 | System.arraycopy(s, 0, this.s, 0, s.length);
119 | }
120 |
121 | /**
122 | * Validate the BigInteger value representing the private key.
123 | * @param secret BigInteger value representing the private key.
124 | */
125 | private void validatePrivateKey(BigInteger secret) {
126 | if (secret.compareTo(BigInteger.ZERO) <= 0) {
127 | throw new InvalidParameterException("Invalid secret");
128 | }
129 | if (party == Party.ALICE) {
130 | if (secret.compareTo(sikeParam.getOrdA()) >= 0) {
131 | throw new InvalidParameterException("Invalid secret");
132 | }
133 | } else if (party == Party.BOB) {
134 | if (secret.compareTo(sikeParam.getOrdB()) >= 0) {
135 | throw new InvalidParameterException("Invalid secret");
136 | }
137 | } else {
138 | throw new InvalidParameterException("Invalid party");
139 | }
140 | }
141 |
142 | /**
143 | * Get the private key length.
144 | * @param party Alice or Bob.
145 | * @return Private key length.
146 | */
147 | private int getKeyLength(Party party) {
148 | if (party == Party.ALICE) {
149 | return (sikeParam.getBitsA() + 7) / 8;
150 | } else if (party == Party.BOB){
151 | return (sikeParam.getBitsB() - 1 + 7) / 8;
152 | } else {
153 | throw new InvalidParameterException("Invalid party");
154 | }
155 | }
156 |
157 | /**
158 | * Get the private key as byte array.
159 | * @return Private key as byte array.
160 | */
161 | public byte[] getKey() {
162 | byte[] keyBytes = new byte[key.length];
163 | System.arraycopy(key, 0, keyBytes, 0, key.length);
164 | return keyBytes;
165 | }
166 |
167 | /**
168 | * Get the private key as an F(p) element.
169 | * @return Private key as an F(p) element.
170 | */
171 | public FpElement getFpElement() {
172 | BigInteger secret = ByteEncoding.fromByteArray(key);
173 | return sikeParam.getFp2ElementFactory().generate(secret).getX0();
174 | }
175 |
176 | /**
177 | * Get the private key as a number.
178 | * @return Private key as a number.
179 | */
180 | public BigInteger getM() {
181 | return ByteEncoding.fromByteArray(key);
182 | }
183 |
184 | /**
185 | * Get parameter s for decapsulation.
186 | * @return Parameter s for decapsulation.
187 | */
188 | public byte[] getS() {
189 | return s;
190 | }
191 |
192 | @Override
193 | public String getAlgorithm() {
194 | return sikeParam.getName();
195 | }
196 |
197 | @Override
198 | public String getFormat() {
199 | // ASN.1 encoding is not supported
200 | return null;
201 | }
202 |
203 | /**
204 | * Get the private key encoded as bytes.
205 | * @return Private key encoded as bytes.
206 | */
207 | @Override
208 | public byte[] getEncoded() {
209 | byte[] output = new byte[s.length + key.length];
210 | System.arraycopy(s, 0, output, 0, s.length);
211 | System.arraycopy(key, 0, output, s.length, key.length);
212 | return output;
213 | }
214 |
215 | /**
216 | * Convert private key into an octet string.
217 | * @return Octet string.
218 | */
219 | public String toOctetString() {
220 | String prefix = OctetEncoding.toOctetString(s, sikeParam.getMessageBytes());
221 | int length = getKeyLength(party);
222 | return prefix + OctetEncoding.toOctetString(key, length);
223 | }
224 |
225 | @Override
226 | public String toString() {
227 | return getM().toString();
228 | }
229 |
230 | @Override
231 | public boolean equals(Object o) {
232 | if (this == o) return true;
233 | if (o == null || getClass() != o.getClass()) return false;
234 | SidhPrivateKey that = (SidhPrivateKey) o;
235 | // Use constant time comparison to avoid timing attacks
236 | return sikeParam.equals(that.sikeParam)
237 | && SideChannelUtil.constantTimeAreEqual(getEncoded(), that.getEncoded());
238 | }
239 |
240 | @Override
241 | public int hashCode() {
242 | return Objects.hash(sikeParam, Arrays.hashCode(s), Arrays.hashCode(key));
243 | }
244 | }
245 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/model/SidhPublicKey.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.model;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.param.SikeParam;
21 | import com.wultra.security.pqc.sike.util.ByteEncoding;
22 | import com.wultra.security.pqc.sike.util.OctetEncoding;
23 | import org.bouncycastle.util.Arrays;
24 |
25 | import java.math.BigInteger;
26 | import java.nio.charset.StandardCharsets;
27 | import java.security.PublicKey;
28 | import java.util.Objects;
29 |
30 | /**
31 | * SIDH or SIKE public key.
32 | *
33 | * @author Roman Strobl, roman.strobl@wultra.com
34 | */
35 | public class SidhPublicKey implements PublicKey {
36 |
37 | private final SikeParam sikeParam;
38 |
39 | private final Fp2Element px;
40 | private final Fp2Element qx;
41 | private final Fp2Element rx;
42 |
43 | /**
44 | * Public key constructor from F(p^2) Elements.
45 | * @param sikeParam SIKE parameters.
46 | * @param px The x coordinate of public point P.
47 | * @param qx The x coordinate of public point Q.
48 | * @param rx The x coordinate of public point R.
49 | */
50 | public SidhPublicKey(SikeParam sikeParam, Fp2Element px, Fp2Element qx, Fp2Element rx) {
51 | this.sikeParam = sikeParam;
52 | this.px = px;
53 | this.qx = qx;
54 | this.rx = rx;
55 | }
56 |
57 | /**
58 | * Public key constructor from byte array representation.
59 | * @param sikeParam SIKE parameters.
60 | * @param bytes The x coordinates of public points P, Q and R.
61 | */
62 | public SidhPublicKey(SikeParam sikeParam, byte[] bytes) {
63 | this.sikeParam = sikeParam;
64 | BigInteger prime = sikeParam.getPrime();
65 | int primeSize = (prime.bitLength() + 7) / 8;
66 | if (bytes == null || bytes.length != 6 * primeSize) {
67 | throw new IllegalStateException("Invalid public key");
68 | }
69 | BigInteger[] keyParts = new BigInteger[6];
70 | for (int i = 0; i < 6; i++) {
71 | byte[] keyBytes = new byte[primeSize];
72 | System.arraycopy(bytes, i * primeSize, keyBytes, 0, keyBytes.length);
73 | keyParts[i] = ByteEncoding.fromByteArray(keyBytes);
74 | }
75 | this.px = sikeParam.getFp2ElementFactory().generate(keyParts[0], keyParts[1]);
76 | this.qx = sikeParam.getFp2ElementFactory().generate(keyParts[2], keyParts[3]);
77 | this.rx = sikeParam.getFp2ElementFactory().generate(keyParts[4], keyParts[5]);
78 | }
79 |
80 | /**
81 | * Construct public key from octets.
82 | * @param sikeParam SIKE parameters.
83 | * @param octets Octet value of the private key.
84 | */
85 | public SidhPublicKey(SikeParam sikeParam, String octets) {
86 | this.sikeParam = sikeParam;
87 | BigInteger prime = sikeParam.getPrime();
88 | int primeSize = (prime.bitLength() + 7) / 8;
89 | if (octets == null || octets.length() != 12 * primeSize) {
90 | throw new IllegalStateException("Invalid public key");
91 | }
92 | byte[] octetBytes = octets.getBytes(StandardCharsets.UTF_8);
93 | BigInteger[] keyParts = new BigInteger[6];
94 | for (int i = 0; i < 6; i++) {
95 | byte[] keyBytes = new byte[primeSize * 2];
96 | System.arraycopy(octetBytes, i * primeSize * 2, keyBytes, 0, keyBytes.length);
97 | keyParts[i] = OctetEncoding.fromOctetString(new String(keyBytes));
98 | }
99 | this.px = sikeParam.getFp2ElementFactory().generate(keyParts[0], keyParts[1]);
100 | this.qx = sikeParam.getFp2ElementFactory().generate(keyParts[2], keyParts[3]);
101 | this.rx = sikeParam.getFp2ElementFactory().generate(keyParts[4], keyParts[5]);
102 | }
103 |
104 | /**
105 | * Get the x coordinate of public point P.
106 | * @return The x coordinate of public point P.
107 | */
108 | public Fp2Element getPx() {
109 | return px;
110 | }
111 |
112 | /**
113 | * The x coordinate of public point Q.
114 | * @return The x coordinate of public point Q.
115 | */
116 | public Fp2Element getQx() {
117 | return qx;
118 | }
119 |
120 | /**
121 | * The x coordinate of public point R.
122 | * @return The x coordinate of public point R.
123 | */
124 | public Fp2Element getRx() {
125 | return rx;
126 | }
127 |
128 | @Override
129 | public String getAlgorithm() {
130 | return sikeParam.getName();
131 | }
132 |
133 | @Override
134 | public String getFormat() {
135 | // ASN.1 encoding is not supported
136 | return null;
137 | }
138 |
139 | /**
140 | * Get the public key encoded as bytes.
141 | * @return Public key encoded as bytes.
142 | */
143 | @Override
144 | public byte[] getEncoded() {
145 | byte[] pxEncoded = px.getEncoded();
146 | byte[] qxEncoded = qx.getEncoded();
147 | byte[] rxEncoded = rx.getEncoded();
148 | byte[] encoded = new byte[pxEncoded.length + qxEncoded.length + rxEncoded.length];
149 | System.arraycopy(pxEncoded, 0, encoded, 0, pxEncoded.length);
150 | System.arraycopy(qxEncoded, 0, encoded, pxEncoded.length, qxEncoded.length);
151 | System.arraycopy(rxEncoded, 0, encoded, pxEncoded.length + qxEncoded.length, rxEncoded.length);
152 | return encoded;
153 | }
154 |
155 | /**
156 | * Convert public key to octet string.
157 | * @return Octet string.
158 | */
159 | public String toOctetString() {
160 | return px.toOctetString() + qx.toOctetString() + rx.toOctetString();
161 | }
162 |
163 | @Override
164 | public String toString() {
165 | return "(" + px.toString() + ", " + qx.toString() + ", " + rx.toString() + ")";
166 | }
167 |
168 | @Override
169 | public boolean equals(Object o) {
170 | if (this == o) return true;
171 | if (o == null || getClass() != o.getClass()) return false;
172 | SidhPublicKey that = (SidhPublicKey) o;
173 | // Use constant time comparison to avoid timing attacks
174 | return sikeParam.equals(that.sikeParam)
175 | && Arrays.constantTimeAreEqual(getEncoded(), that.getEncoded());
176 | }
177 |
178 | @Override
179 | public int hashCode() {
180 | return Objects.hash(sikeParam, px, qx, rx);
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/model/optimized/MontgomeryConstants.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.model.optimized;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.param.SikeParam;
21 |
22 | /**
23 | * Montgomery curve constants for optimization in projective coordinates.
24 | *
25 | * @author Roman Strobl, roman.strobl@wultra.com
26 | */
27 | public class MontgomeryConstants {
28 |
29 | private Fp2Element c;
30 | private Fp2Element a24plus;
31 | private Fp2Element a24minus;
32 | private Fp2Element c24;
33 | private Fp2Element k1;
34 | private Fp2Element k2;
35 | private Fp2Element k3;
36 |
37 | /**
38 | * Default optimized montgomery constants constructor.
39 | * @param sikeParam SIKE parameters.
40 | */
41 | public MontgomeryConstants(SikeParam sikeParam) {
42 | c = sikeParam.getFp2ElementFactory().one();
43 | }
44 |
45 | /**
46 | * Optimized montgomery constants constructor with calculation of constants.
47 | * @param sikeParam SIKE parameters.
48 | * @param a Montgomery curve coefficient a.
49 | */
50 | public MontgomeryConstants(SikeParam sikeParam, Fp2Element a) {
51 | this(sikeParam);
52 | Fp2Element t1 = c.add(c);
53 | this.a24plus = a.add(t1);
54 | this.a24minus = a.subtract(t1);
55 | this.c24 = t1.add(t1);
56 | }
57 |
58 | /**
59 | * Get Montgomery curve constant c.
60 | * @return Montgomery constant c.
61 | */
62 | public Fp2Element getC() {
63 | return c;
64 | }
65 |
66 | /**
67 | * Set Montgomery curve constant c.
68 | * @param c Montgomery curve constant c.
69 | */
70 | public void setC(Fp2Element c) {
71 | this.c = c;
72 | }
73 |
74 | /**
75 | * Get Montgomery curve constant a24+.
76 | * @return Montgomery curve constant a24+.
77 | */
78 | public Fp2Element getA24plus() {
79 | return a24plus;
80 | }
81 |
82 | /**
83 | * Set Montgomery curve constant a24+.
84 | * @param a24plus Montgomery curve constant a24+.
85 | */
86 | public void setA24plus(Fp2Element a24plus) {
87 | this.a24plus = a24plus;
88 | }
89 |
90 | /**
91 | * Get Montgomery curve constant a24-.
92 | * @return Montgomery curve constant a24-.
93 | */
94 | public Fp2Element getA24minus() {
95 | return a24minus;
96 | }
97 |
98 | /**
99 | * Set Montgomery curve constant a24-.
100 | * @param a24minus Montgomery curve constant a24-.
101 | */
102 | public void setA24minus(Fp2Element a24minus) {
103 | this.a24minus = a24minus;
104 | }
105 |
106 | /**
107 | * Get Montgomery curve constant c24.
108 | * @return Montgomery curve constant c24.
109 | */
110 | public Fp2Element getC24() {
111 | return c24;
112 | }
113 |
114 | /**
115 | * Set Montgomery curve constant c24.
116 | * @param c24 Montgomery curve constant c24.
117 | */
118 | public void setC24(Fp2Element c24) {
119 | this.c24 = c24;
120 | }
121 |
122 | /**
123 | * Get Montgomery curve constant K1.
124 | * @return Montgomery curve constant K1.
125 | */
126 | public Fp2Element getK1() {
127 | return k1;
128 | }
129 |
130 | /**
131 | * Set Montgomery curve constant K2.
132 | * @param k1 Montgomery curve constant K2.
133 | */
134 | public void setK1(Fp2Element k1) {
135 | this.k1 = k1;
136 | }
137 |
138 | /**
139 | * Get Montgomery curve constant K2.
140 | * @return Montgomery curve constant K2.
141 | */
142 | public Fp2Element getK2() {
143 | return k2;
144 | }
145 |
146 | /**
147 | * Set Montgomery curve constant K2.
148 | * @param k2 Montgomery curve constant K2.
149 | */
150 | public void setK2(Fp2Element k2) {
151 | this.k2 = k2;
152 | }
153 |
154 | /**
155 | * Get Montgomery curve constant K3.
156 | * @return Montgomery curve constant K3.
157 | */
158 | public Fp2Element getK3() {
159 | return k3;
160 | }
161 |
162 | /**
163 | * Set Montgomery curve constant K3.
164 | * @param k3 Montgomery curve constant K3.
165 | */
166 | public void setK3(Fp2Element k3) {
167 | this.k3 = k3;
168 | }
169 |
170 | @Override
171 | public String toString() {
172 | return "MontgomeryConstants{" +
173 | "c=" + c +
174 | ", a24plus=" + a24plus +
175 | ", a24minus=" + a24minus +
176 | ", c24=" + c24 +
177 | ", k1=" + k1 +
178 | ", k2=" + k2 +
179 | ", k3=" + k3 +
180 | '}';
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/param/SikeParam.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.param;
18 |
19 | import com.wultra.security.pqc.sike.math.api.*;
20 | import com.wultra.security.pqc.sike.math.optimized.fp.FpElementOpti;
21 | import com.wultra.security.pqc.sike.model.ImplementationType;
22 |
23 | import java.math.BigInteger;
24 |
25 | /**
26 | * SIKE parameters.
27 | *
28 | * @author Roman Strobl, roman.strobl@wultra.com
29 | */
30 | public interface SikeParam {
31 |
32 | /**
33 | * Get implementation type.
34 | * @return Implementation type.
35 | */
36 | ImplementationType getImplementationType();
37 |
38 | /**
39 | * Factory for Fp2Elements.
40 | * @return Factory for Fp2Elements.
41 | */
42 | Fp2ElementFactory getFp2ElementFactory();
43 |
44 | /**
45 | * Get Montgomery curve math algorithms.
46 | * @return Montgomery curve math algorithms.
47 | */
48 | Montgomery getMontgomery();
49 |
50 | /**
51 | * Get Isogeny curve algorithms.
52 | * @return Isogeny curve algorithms.
53 | */
54 | Isogeny getIsogeny();
55 |
56 | /**
57 | * Get SIKE variant name.
58 | * @return SIKE variant name.
59 | */
60 | String getName();
61 |
62 | /**
63 | * Get Montgomery coefficient a for starting curve.
64 | * @return Montgomery coefficient a for starting curve.
65 | */
66 | Fp2Element getA();
67 |
68 | /**
69 | * Get Montgomery coefficient b for starting curve.
70 | * @return Montgomery coefficient b for starting curve.
71 | */
72 | Fp2Element getB();
73 |
74 | /**
75 | * Get parameter eA.
76 | * @return Parameter eA.
77 | */
78 | int getEA();
79 |
80 | /**
81 | * Get parameter eB.
82 | * @return Parameter eB.
83 | */
84 | int getEB();
85 |
86 | /**
87 | * Get factor of A.
88 | * @return Factor of A.
89 | */
90 | BigInteger getOrdA();
91 |
92 | /**
93 | * Get factor of B.
94 | * @return Factor of b.
95 | */
96 | BigInteger getOrdB();
97 |
98 | /**
99 | * Get most significant bit of A.
100 | * @return Most significant bit of A.
101 | */
102 | int getBitsA();
103 |
104 | /**
105 | * Get most significant bit of B.
106 | * @return Most significant bit of B.
107 | */
108 | int getBitsB();
109 |
110 | /**
111 | * Get mask used for key generation of A.
112 | * @return Mask used for key generation of A.
113 | */
114 | byte getMaskA();
115 |
116 | /**
117 | * Get mask used for key generation of B.
118 | * @return Mask used for key generation of B.
119 | */
120 | byte getMaskB();
121 |
122 | /**
123 | * Get field prime.
124 | * @return Field prime.
125 | */
126 | BigInteger getPrime();
127 |
128 | /**
129 | * Get point PA.
130 | * @return point PA.
131 | */
132 | Fp2Point getPA();
133 |
134 | /**
135 | * Get point QA.
136 | * @return point QA.
137 | */
138 | Fp2Point getQA();
139 |
140 | /**
141 | * Get point RA.
142 | * @return point RA.
143 | */
144 | Fp2Point getRA();
145 |
146 | /**
147 | * Get point PB.
148 | * @return point PB.
149 | */
150 | Fp2Point getPB();
151 |
152 | /**
153 | * Get point QB.
154 | * @return point QB.
155 | */
156 | Fp2Point getQB();
157 |
158 | /**
159 | * Get point RB.
160 | * @return point RB.
161 | */
162 | Fp2Point getRB();
163 |
164 | /**
165 | * Get the number of bytes used for cryptography operations.
166 | * @return Number of bytes used for cryptography operations.
167 | */
168 | int getCryptoBytes();
169 |
170 | /**
171 | * Get the number of bytes used for message operations.
172 | * @return Number of bytes used for message operations.
173 | */
174 | int getMessageBytes();
175 |
176 | /**
177 | * Get number of rows for optimized tree computations in the 2-isogeny graph.
178 | * @return Number of rows for optimized tree computations in the 2-isogeny graph.
179 | */
180 | int getTreeRowsA();
181 |
182 | /**
183 | * Get number of rows for optimized tree computations in the 3-isogeny graph.
184 | * @return Number of rows for optimized tree computations in the 3-isogeny graph.
185 | */
186 | int getTreeRowsB();
187 |
188 | /**
189 | * Get maximum number of points for optimized tree computations in the 2-isogeny graph.
190 | * @return Maxim number of points for optimized tree computations in the 2-isogeny graph.
191 | */
192 | int getTreePointsA();
193 |
194 | /**
195 | * Get maximum number of points for optimized tree computations in the 3-isogeny graph.
196 | * @return Maxim number of points for optimized tree computations in the 3-isogeny graph.
197 | */
198 | int getTreePointsB();
199 |
200 | /**
201 | * Get optimization strategy for tree computations in the 2-isogeny graph.
202 | * @return Optimization strategy for tree computations in the 2-isogeny graph.
203 | */
204 | int[] getStrategyA();
205 |
206 | /**
207 | * Get optimization strategy for tree computations in the 3-isogeny graph.
208 | * @return Optimization strategy for tree computations in the 3-isogeny graph.
209 | */
210 | int[] getStrategyB();
211 |
212 | /**
213 | * Get size of long array for optimized elements.
214 | * @return Size of long array.
215 | */
216 | int getFpWords();
217 |
218 | /**
219 | * Get number of 0 digits in the least significant part of p + 1.
220 | * @return Number of 0 digits in the least significant part of p + 1.
221 | */
222 | int getZeroWords();
223 |
224 | /**
225 | * Get optimized field prime p.
226 | * @return Field prime p.
227 | */
228 | FpElementOpti getP();
229 |
230 | /**
231 | * Get optimized value p + 1.
232 | * @return Value p + 1.
233 | */
234 | FpElementOpti getP1();
235 |
236 | /**
237 | * Get optimized value p * 2.
238 | * @return Value p * 2.
239 | */
240 | FpElementOpti getPx2();
241 |
242 | /**
243 | * Get optimized value pR2.
244 | * @return Optimized value pR2.
245 | */
246 | FpElementOpti getPR2();
247 |
248 | /**
249 | * Get the power strategy for the p34 algorithm.
250 | * @return Power strategy.
251 | */
252 | int[] getPowStrategy();
253 |
254 | /**
255 | * Get the multiplication strategy for the p34 algorithm.
256 | * @return Multiplication strategy.
257 | */
258 | int[] getMulStrategy();
259 |
260 | /**
261 | * Get initial multiplication value for the p34 algorithm.
262 | * @return Initial multiplication value for the p34 algorithm
263 | */
264 | int getInitialMul();
265 |
266 | }
267 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/util/ByteEncoding.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.util;
18 |
19 | import org.bouncycastle.util.BigIntegers;
20 |
21 | import java.math.BigInteger;
22 | import java.security.InvalidParameterException;
23 |
24 | /**
25 | * Converter for byte encoding for compatibility with the GMP library.
26 | *
27 | * @author Roman Strobl, roman.strobl@wultra.com
28 | */
29 | public class ByteEncoding {
30 |
31 | private ByteEncoding() {
32 |
33 | }
34 |
35 | /**
36 | * Convert unsigned number from byte array. The byte array is stored in big-endian ordering.
37 | *
38 | * @param data Byte array representing the number.
39 | * @return Converted number.
40 | */
41 | public static BigInteger fromByteArray(byte[] data) {
42 | return BigIntegers.fromUnsignedByteArray(reverse(data));
43 | }
44 |
45 | /**
46 | * Convert unsigned number into a byte array. The byte array is stored in big-endian ordering.
47 | * @param n Number to convert.
48 | * @param length Length of byte array.
49 | * @return Byte array representing converted number.
50 | */
51 | public static byte[] toByteArray(BigInteger n, int length) {
52 | byte[] encoded = reverse(BigIntegers.asUnsignedByteArray(n));
53 | if (encoded.length > length) {
54 | throw new InvalidParameterException("Number is too large");
55 | }
56 | if (encoded.length == length) {
57 | return encoded;
58 | }
59 | byte[] padded = new byte[length];
60 | System.arraycopy(encoded, 0, padded, 0, encoded.length);
61 | return padded;
62 | }
63 |
64 | /**
65 | * Reverse byte array.
66 | * @param data Source byte array.
67 | * @return Reversed byte array.
68 | */
69 | private static byte[] reverse(byte[] data) {
70 | byte[] out = new byte[data.length];
71 | for(int i = 0; i < data.length; i++) {
72 | out[i] = data[data.length - i - 1];
73 | }
74 | return out;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/util/OctetEncoding.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.util;
18 |
19 | import java.math.BigInteger;
20 | import java.security.InvalidParameterException;
21 |
22 | /**
23 | * Converter for octet encoding specified in SIKE specification.
24 | *
25 | * @author Roman Strobl, roman.strobl@wultra.com
26 | */
27 | public class OctetEncoding {
28 |
29 | private OctetEncoding() {
30 |
31 | }
32 |
33 | /**
34 | * Convert a BigInteger into octet string.
35 | *
36 | * @param n A non-negative number to convert.
37 | * @param length Length of generated octet string specified as number of octets.
38 | * @return Converted octet string.
39 | */
40 | public static String toOctetString(BigInteger n, int length) {
41 | if (n.signum() == -1) {
42 | throw new InvalidParameterException("Number is negative");
43 | }
44 | String hex = n.toString(16).toUpperCase();
45 | if (hex.length() % 2 == 1) {
46 | hex = "0" + hex;
47 | }
48 | char[] chars = hex.toCharArray();
49 | int expectedLength = length * 2;
50 | if (chars.length > expectedLength) {
51 | throw new InvalidParameterException("Number is too large, length: " + chars.length + ", expected: " + expectedLength);
52 | }
53 | StringBuilder sb = new StringBuilder();
54 | for (int i = hex.length() - 1; i >= 0; i -= 2) {
55 | sb.append(chars[i - 1]);
56 | sb.append(chars[i]);
57 | }
58 | for (int i = 0; i < expectedLength - chars.length; i++) {
59 | sb.append("0");
60 | }
61 | return sb.toString();
62 | }
63 |
64 | /**
65 | * Convert a byte array representing a number into an octet string.
66 | *
67 | * @param data Byte array representing a number.
68 | * @param length Length of generated octet string specified as number of octets.
69 | * @return Converted octet string.
70 | */
71 | public static String toOctetString(byte[] data, int length) {
72 | return toOctetString(ByteEncoding.fromByteArray(data), length);
73 | }
74 |
75 |
76 | /**
77 | * Convert an octet string into BigInteger.
78 | *
79 | * @param str Octet string.
80 | * @return Converted BigInteger value.
81 | */
82 | public static BigInteger fromOctetString(String str) {
83 | if (str == null || str.length() % 2 == 1) {
84 | throw new InvalidParameterException("Invalid octet string");
85 | }
86 | char[] chars = str.toCharArray();
87 | StringBuilder sb = new StringBuilder();
88 | for (int i = chars.length - 1; i >= 0; i -= 2) {
89 | sb.append(chars[i - 1]);
90 | sb.append(chars[i]);
91 | }
92 | return new BigInteger(sb.toString(), 16);
93 | }
94 |
95 | /**
96 | * Convert an octet string to byte array.
97 | * @param str Octet string.
98 | * @param length Expected length of byte array.
99 | * @return Converted byte array value.
100 | */
101 | public static byte[] fromOctetString(String str, int length) {
102 | return ByteEncoding.toByteArray(fromOctetString(str), length);
103 | }
104 | }
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/util/Sha3.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.util;
18 |
19 | import org.bouncycastle.crypto.digests.SHAKEDigest;
20 |
21 | /**
22 | * SHA-3 hash function SHAKE256 with variable output length.
23 | *
24 | * @author Roman Strobl, roman.strobl@wultra.com
25 | */
26 | public class Sha3 {
27 |
28 | private Sha3() {
29 |
30 | }
31 |
32 | /**
33 | * Hash data using SHAKE256.
34 | * @param data Data to hash.
35 | * @param outputLen Output length.
36 | * @return Hashed data.
37 | */
38 | public static byte[] shake256(byte[] data, int outputLen) {
39 | SHAKEDigest shake256 = new SHAKEDigest(256);
40 | shake256.update(data, 0, data.length);
41 | byte[] hashed = new byte[outputLen];
42 | // Squeeze output to required message length
43 | shake256.doFinal(hashed, 0, outputLen);
44 | return hashed;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/sike-java/src/main/java/com/wultra/security/pqc/sike/util/SideChannelUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.util;
18 |
19 | import org.bouncycastle.util.Arrays;
20 |
21 | /**
22 | * Utilities for preventing side channel attacks.
23 | *
24 | * @author Roman Strobl, roman.strobl@wultra.com
25 | */
26 | public class SideChannelUtil {
27 |
28 | private SideChannelUtil() {
29 |
30 | }
31 |
32 | /**
33 | * Compare two byte arrays in constant time.
34 | * @param bytes1 First byte array.
35 | * @param bytes2 Second byte array.
36 | * @return Whether byte arrays are equal.
37 | */
38 | public static boolean constantTimeAreEqual(byte[] bytes1, byte[] bytes2) {
39 | return Arrays.constantTimeAreEqual(bytes1, bytes2);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/KeyConversionTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike;
18 |
19 | import com.wultra.security.pqc.sike.crypto.KeyGenerator;
20 | import com.wultra.security.pqc.sike.model.ImplementationType;
21 | import com.wultra.security.pqc.sike.model.Party;
22 | import com.wultra.security.pqc.sike.model.SidhPrivateKey;
23 | import com.wultra.security.pqc.sike.model.SidhPublicKey;
24 | import com.wultra.security.pqc.sike.param.SikeParam;
25 | import com.wultra.security.pqc.sike.param.SikeParamP434;
26 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
27 | import org.junit.jupiter.api.Test;
28 |
29 | import java.security.*;
30 |
31 | import static org.junit.jupiter.api.Assertions.assertEquals;
32 |
33 | /**
34 | * Test of key conversions.
35 | *
36 | * @author Roman Strobl, roman.strobl@wultra.com
37 | */
38 | class KeyConversionTest {
39 |
40 | static {
41 | Security.addProvider(new BouncyCastleProvider());
42 | }
43 |
44 | @Test
45 | void testConversionToByteArray() throws GeneralSecurityException {
46 | SikeParam sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
47 | KeyGenerator keyGenerator = new KeyGenerator(sikeParam);
48 | KeyPair keyPairA = keyGenerator.generateKeyPair(Party.ALICE);
49 | KeyPair keyPairB = keyGenerator.generateKeyPair(Party.BOB);
50 | byte[] privKeyBytesA = keyPairA.getPrivate().getEncoded();
51 | byte[] pubKeyBytesA = keyPairA.getPublic().getEncoded();
52 | byte[] privKeyBytesB = keyPairB.getPrivate().getEncoded();
53 | byte[] pubKeyBytesB = keyPairB.getPublic().getEncoded();
54 | PrivateKey privKeyA = new SidhPrivateKey(sikeParam, Party.ALICE, privKeyBytesA);
55 | PublicKey pubKeyA = new SidhPublicKey(sikeParam, pubKeyBytesA);
56 | PrivateKey privKeyB = new SidhPrivateKey(sikeParam, Party.BOB, privKeyBytesB);
57 | PublicKey pubKeyB = new SidhPublicKey(sikeParam, pubKeyBytesB);
58 | assertEquals(privKeyA, keyPairA.getPrivate());
59 | assertEquals(pubKeyA, keyPairA.getPublic());
60 | assertEquals(privKeyB, keyPairB.getPrivate());
61 | assertEquals(pubKeyB, keyPairB.getPublic());
62 | }
63 |
64 | @Test
65 | void testConversionToOctets() throws GeneralSecurityException {
66 | SikeParam sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
67 | KeyGenerator keyGenerator = new KeyGenerator(sikeParam);
68 | KeyPair keyPairA = keyGenerator.generateKeyPair(Party.ALICE);
69 | KeyPair keyPairB = keyGenerator.generateKeyPair(Party.BOB);
70 | String privKeyOctetsA = ((SidhPrivateKey) keyPairA.getPrivate()).toOctetString();
71 | String pubKeyOctetsA = ((SidhPublicKey) keyPairA.getPublic()).toOctetString();
72 | String privKeyOctetsB = ((SidhPrivateKey) keyPairB.getPrivate()).toOctetString();
73 | String pubKeyOctetsB = ((SidhPublicKey) keyPairB.getPublic()).toOctetString();
74 | PrivateKey privKeyA = new SidhPrivateKey(sikeParam, Party.ALICE, privKeyOctetsA);
75 | PublicKey pubKeyA = new SidhPublicKey(sikeParam, pubKeyOctetsA);
76 | PrivateKey privKeyB = new SidhPrivateKey(sikeParam, Party.BOB, privKeyOctetsB);
77 | PublicKey pubKeyB = new SidhPublicKey(sikeParam, pubKeyOctetsB);
78 | assertEquals(privKeyA, keyPairA.getPrivate());
79 | assertEquals(pubKeyA, keyPairA.getPublic());
80 | assertEquals(privKeyB, keyPairB.getPrivate());
81 | assertEquals(pubKeyB, keyPairB.getPublic());
82 | }
83 |
84 | }
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/OctetEncodingTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike;
18 |
19 | import com.wultra.security.pqc.sike.math.optimized.fp.FpElementOpti;
20 | import com.wultra.security.pqc.sike.model.ImplementationType;
21 | import com.wultra.security.pqc.sike.param.*;
22 | import com.wultra.security.pqc.sike.util.OctetEncoding;
23 | import org.junit.jupiter.api.Test;
24 |
25 | import java.math.BigInteger;
26 | import java.security.SecureRandom;
27 |
28 | import static org.junit.jupiter.api.Assertions.assertArrayEquals;
29 | import static org.junit.jupiter.api.Assertions.assertEquals;
30 |
31 | /**
32 | * Test of octet encoding.
33 | *
34 | * @author Roman Strobl, roman.strobl@wultra.com
35 | */
36 | class OctetEncodingTest {
37 |
38 | @Test
39 | void testConversionToString() {
40 | assertEquals("000000", OctetEncoding.toOctetString(BigInteger.ZERO, 3));
41 | assertEquals("010000000000", OctetEncoding.toOctetString(BigInteger.ONE, 6));
42 | assertEquals("02010000000000000000", OctetEncoding.toOctetString(new BigInteger("258"), 10));
43 | assertEquals("F5D2847EB0AD708A836E3A42DCF8A06DD6A442E58584EEFCFB93E3643370A9D2B2D7A1FBD32FCA430B640DF746789886F55B0F9123AB00", OctetEncoding.toOctetString(new BigInteger("7414245793236218931759067416133656081091359987964242955586558871517284227355106165661062279519102988920114614398938767562664891125"), 55));
44 | assertEquals("CF6121E44395DFAE78152A1162C49E3196B6065E8781FA4FC53F971E1766818E81388CB3BE212446A06AFBCEC958BE4E6539A590619100", OctetEncoding.toOctetString(new BigInteger("6298340736269152096363706376601736707467340295126624700837062780723222842097560939735075361277996916624015901459649381975340442063"), 55));
45 | }
46 |
47 | @Test
48 | void testConversionFromString() {
49 | assertEquals(BigInteger.ZERO, OctetEncoding.fromOctetString("000000"));
50 | assertEquals(BigInteger.ONE, OctetEncoding.fromOctetString("010000000000"));
51 | assertEquals(new BigInteger("258"), OctetEncoding.fromOctetString("02010000000000000000"));
52 | assertEquals(new BigInteger("7414245793236218931759067416133656081091359987964242955586558871517284227355106165661062279519102988920114614398938767562664891125"), OctetEncoding.fromOctetString("F5D2847EB0AD708A836E3A42DCF8A06DD6A442E58584EEFCFB93E3643370A9D2B2D7A1FBD32FCA430B640DF746789886F55B0F9123AB00"));
53 | assertEquals(new BigInteger("6298340736269152096363706376601736707467340295126624700837062780723222842097560939735075361277996916624015901459649381975340442063"), OctetEncoding.fromOctetString("CF6121E44395DFAE78152A1162C49E3196B6065E8781FA4FC53F971E1766818E81388CB3BE212446A06AFBCEC958BE4E6539A590619100"));
54 | }
55 |
56 | @Test
57 | void testConversions() {
58 | SecureRandom secureRandom = new SecureRandom();
59 | for (int i = 0; i < 100; i++) {
60 | BigInteger r = new BigInteger(i, secureRandom);
61 | int mlen = i / 8 + 1;
62 | assertEquals(r, OctetEncoding.fromOctetString(OctetEncoding.toOctetString(r, mlen)));
63 | }
64 | }
65 |
66 | @Test
67 | void testConversionToMontgomeryP434One() {
68 | SikeParam sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
69 | FpElementOpti one = new FpElementOpti(sikeParam, new BigInteger("1"));
70 | assertArrayEquals(new long[]{
71 | 0x000000000000742CL,
72 | 0x0000000000000000L,
73 | 0x0000000000000000L,
74 | 0xB90FF404FC000000L,
75 | 0xD801A4FB559FACD4L,
76 | 0xE93254545F77410CL,
77 | 0x0000ECEEA7BD2EDAL
78 | }, one.getValue());
79 | String octetString = one.toOctetString();
80 | assertEquals("01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", octetString);
81 | assertEquals(new BigInteger("1"), OctetEncoding.fromOctetString(octetString));
82 | }
83 |
84 | @Test
85 | void testConversionFromMontgomeryP434() {
86 | SikeParam sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
87 | FpElementOpti six = new FpElementOpti(sikeParam, new long[]{
88 | 0x000000000002B90AL,
89 | 0x0000000000000000L,
90 | 0x0000000000000000L,
91 | 0x5ADCCB2822000000L,
92 | 0x187D24F39F0CAFB4L,
93 | 0x9D353A4D394145A0L,
94 | 0x00012559A0403298L
95 | });
96 | String octetString = six.toOctetString();
97 | assertEquals("06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", octetString);
98 | assertEquals(new BigInteger("6"), OctetEncoding.fromOctetString(octetString));
99 | }
100 |
101 | @Test
102 | void testConversionToMontgomeryP434Six() {
103 | SikeParam sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
104 | FpElementOpti six = new FpElementOpti(sikeParam, new BigInteger("6"));
105 | assertArrayEquals(new long[]{
106 | 0x000000000002B90AL,
107 | 0x0000000000000000L,
108 | 0x0000000000000000L,
109 | 0x5ADCCB2822000000L,
110 | 0x187D24F39F0CAFB4L,
111 | 0x9D353A4D394145A0L,
112 | 0x00012559A0403298L
113 | }, six.getValue());
114 | String octetString = six.toOctetString();
115 | assertEquals("06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", octetString);
116 | assertEquals(new BigInteger("6"), OctetEncoding.fromOctetString(octetString));
117 | }
118 |
119 | @Test
120 | void testConversionFromMontgomeryP503() {
121 | SikeParam sikeParam = new SikeParamP503(ImplementationType.OPTIMIZED);
122 | FpElementOpti six = new FpElementOpti(sikeParam, new long[]{
123 | 0x00000000000017D8L,
124 | 0x0000000000000000L,
125 | 0x0000000000000000L,
126 | 0xE000000000000000L,
127 | 0x30B1E6E3A51520FAL,
128 | 0xB13BC3BF6FFB3992L,
129 | 0x8045412EEB3E3DEDL,
130 | 0x0069182E2159DBB8L
131 | });
132 | String octetString = six.toOctetString();
133 | assertEquals("060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", octetString);
134 | assertEquals(new BigInteger("6"), OctetEncoding.fromOctetString(octetString));
135 | }
136 |
137 | @Test
138 | void testConversionFromMontgomeryP610() {
139 | SikeParam sikeParam = new SikeParamP610(ImplementationType.OPTIMIZED);
140 | FpElementOpti one = new FpElementOpti(sikeParam, new long[]{
141 | 0x00000000670CC8E6L,
142 | 0x0000000000000000L,
143 | 0x0000000000000000L,
144 | 0x0000000000000000L,
145 | 0x9A34000000000000L,
146 | 0x4D99C2BD28717A3FL,
147 | 0x0A4A1839A323D41CL,
148 | 0xD2B62215D06AD1E2L,
149 | 0x1369026E862CAF3DL,
150 | 0x000000010894E964L
151 | });
152 | String octetString = one.toOctetString();
153 | assertEquals("0100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", octetString);
154 | assertEquals(BigInteger.ONE, OctetEncoding.fromOctetString(octetString));
155 | }
156 |
157 | @Test
158 | void testConversionFromMontgomeryP751() {
159 | SikeParam sikeParam = new SikeParamP751(ImplementationType.OPTIMIZED);
160 | FpElementOpti one = new FpElementOpti(sikeParam, new long[]{
161 | 0x00000000000249ADL,
162 | 0x0000000000000000L,
163 | 0x0000000000000000L,
164 | 0x0000000000000000L,
165 | 0x0000000000000000L,
166 | 0x8310000000000000L,
167 | 0x5527B1E4375C6C66L,
168 | 0x697797BF3F4F24D0L,
169 | 0xC89DB7B2AC5C4E2EL,
170 | 0x4CA4B439D2076956L,
171 | 0x10F7926C7512C7E9L,
172 | 0x00002D5B24BCE5E2L
173 | });
174 | String octetString = one.toOctetString();
175 | assertEquals("01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", octetString);
176 | assertEquals(new BigInteger("1"), OctetEncoding.fromOctetString(octetString));
177 | }
178 |
179 | // TODO - more conversion tests
180 |
181 | }
182 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/SidhTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike;
18 |
19 | import com.wultra.security.pqc.sike.crypto.KeyGenerator;
20 | import com.wultra.security.pqc.sike.crypto.Sidh;
21 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
22 | import com.wultra.security.pqc.sike.model.ImplementationType;
23 | import com.wultra.security.pqc.sike.model.Party;
24 | import com.wultra.security.pqc.sike.param.SikeParam;
25 | import com.wultra.security.pqc.sike.param.SikeParamP434;
26 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
27 | import org.junit.jupiter.api.Test;
28 |
29 | import java.security.GeneralSecurityException;
30 | import java.security.KeyPair;
31 | import java.security.Security;
32 |
33 | import static org.junit.jupiter.api.Assertions.assertTrue;
34 |
35 | /**
36 | * Test of SIDH key exchange.
37 | *
38 | * @author Roman Strobl, roman.strobl@wultra.com
39 | */
40 | class SidhTest {
41 |
42 | static {
43 | Security.addProvider(new BouncyCastleProvider());
44 | }
45 |
46 | @Test
47 | void testSidh() throws GeneralSecurityException {
48 | SikeParam sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
49 | System.out.println("Prime: " + sikeParam.getPrime());
50 | KeyGenerator keyGenerator = new KeyGenerator(sikeParam);
51 | Sidh sidh = new Sidh(sikeParam);
52 | int loopCount = 10;
53 | long timeTotalA = 0L;
54 | long timeTotalB = 0L;
55 | for (int i = 0; i < loopCount; i++) {
56 | System.out.println("----------------------------------------");
57 | long timeStartA = System.currentTimeMillis();
58 | KeyPair keyPairA = keyGenerator.generateKeyPair(Party.ALICE);
59 | System.out.println("Alice's keypair:");
60 | System.out.println("Private key: " + keyPairA.getPrivate());
61 | System.out.println("Public key: " + keyPairA.getPublic());
62 | long timeEndA = System.currentTimeMillis();
63 | timeTotalA += (timeEndA - timeStartA);
64 |
65 | long timeStartB = System.currentTimeMillis();
66 | KeyPair keyPairB = keyGenerator.generateKeyPair(Party.BOB);
67 | System.out.println("Bob's keypair:");
68 | System.out.println("Private key: " + keyPairB.getPrivate());
69 | System.out.println("Public key: " + keyPairB.getPublic());
70 | long timeEndB = System.currentTimeMillis();
71 | timeTotalB += (timeEndB - timeStartB);
72 |
73 | // Bob's public key is sent to Alice
74 | timeStartA = System.currentTimeMillis();
75 | Fp2Element secretA = sidh.generateSharedSecret(Party.ALICE, keyPairA.getPrivate(), keyPairB.getPublic());
76 | System.out.println("Shared secret generated by Alice: " + secretA);
77 | timeEndA = System.currentTimeMillis();
78 | timeTotalA += (timeEndA - timeStartA);
79 |
80 | // Alice's public key is sent to Bob
81 | timeStartB = System.currentTimeMillis();
82 | Fp2Element secretB = sidh.generateSharedSecret(Party.BOB, keyPairB.getPrivate(), keyPairA.getPublic());
83 | System.out.println("Shared secret generated by Bob: " + secretB);
84 | timeEndB = System.currentTimeMillis();
85 | timeTotalB += (timeEndB - timeStartB);
86 |
87 | boolean match = secretA.equals(secretB);
88 | System.out.println("Secrets match: " + match);
89 | assertTrue(match, "Secrets do not match");
90 | }
91 | System.out.println("Average execution time (Alice): " + ((double)timeTotalA / loopCount) + " ms");
92 | System.out.println("Average execution time (Bob): " + ((double)timeTotalB / loopCount) + " ms");
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/SikeDeterministicTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike;
18 |
19 | import com.wultra.security.pqc.sike.crypto.KeyGenerator;
20 | import com.wultra.security.pqc.sike.crypto.RandomGenerator;
21 | import com.wultra.security.pqc.sike.crypto.Sike;
22 | import com.wultra.security.pqc.sike.kat.util.CrtDrbgRandom;
23 | import com.wultra.security.pqc.sike.model.*;
24 | import com.wultra.security.pqc.sike.param.SikeParam;
25 | import com.wultra.security.pqc.sike.param.SikeParamP434;
26 | import com.wultra.security.pqc.sike.util.OctetEncoding;
27 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
28 | import org.bouncycastle.util.encoders.Base64;
29 | import org.bouncycastle.util.encoders.Hex;
30 | import org.junit.jupiter.api.Test;
31 |
32 | import java.security.GeneralSecurityException;
33 | import java.security.KeyPair;
34 | import java.security.Security;
35 | import java.util.Arrays;
36 |
37 | import static org.junit.jupiter.api.Assertions.assertEquals;
38 | import static org.junit.jupiter.api.Assertions.assertTrue;
39 |
40 | /**
41 | * Test of randomness using seed provided to a CRT DRBG random generator in a known SIKE decapsulation.
42 | *
43 | * @author Roman Strobl, roman.strobl@wultra.com
44 | */
45 | class SikeDeterministicTest {
46 |
47 | private static final String SEED = "061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1";
48 |
49 | static {
50 | Security.addProvider(new BouncyCastleProvider());
51 | }
52 |
53 | @Test
54 | void testDeterministicSike() throws GeneralSecurityException {
55 | System.out.println("----------------------------------------");
56 | SikeParam sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
57 | System.out.println("Prime: " + sikeParam.getPrime());
58 | byte[] seedBytes = Hex.decode(SEED);
59 | CrtDrbgRandom drbgRandom = new CrtDrbgRandom(seedBytes);
60 | KeyGenerator keyGenerator = new KeyGenerator(sikeParam, new RandomGenerator(drbgRandom));
61 | KeyPair keyPair = keyGenerator.generateKeyPair(Party.BOB);
62 | SidhPrivateKey priv = (SidhPrivateKey) keyPair.getPrivate();
63 | SidhPublicKey pub = (SidhPublicKey) keyPair.getPublic();
64 | assertEquals("7C9935A0B07694AA0C6D10E4DB6B1ADD91282214654CB55E7C2CACD53919604D5BAC7B23EEF4B315FEEF5E01", priv.toOctetString());
65 | assertEquals("4484D7AADB44B40CC180DC568B2C142A60E6E2863F5988614A6215254B2F5F6F79B48F329AD1A2DED20B7ABAB10F7DBF59C3E20B59A700093060D2A44ACDC0083A53CF0808E0B3A827C45176BEE0DC6EC7CC16461E38461C12451BB95191407C1E942BB50D4C7B25A49C644B630159E6C403653838E689FBF4A7ADEA693ED0657BA4A724786AF7953F7BA6E15F9BBF9F5007FB711569E72ACAB05D3463A458536CAB647F00C205D27D5311B2A5113D4B26548000DB237515931A040804E769361F94FF0167C78353D2630A1E6F595A1F80E87F6A5BCD679D7A64C5006F6191D4ADEFA1EA67F6388B7017D453F4FE2DFE80CCC709000B52175BFC3ADE52ECCB0CEBE1654F89D39131C357EACB61E5F13C80AB0165B7714D6BE6DF65F8DE73FF47B7F3304639F0903653ECCFA252F6E2104C4ABAD3C33AF24FD0E56F58DB92CC66859766035419AB2DF600", pub.toOctetString());
66 |
67 | Sike sike = new Sike(sikeParam, drbgRandom);
68 | EncapsulationResult encapsulationResult = sike.encapsulate(keyPair.getPublic());
69 | EncryptedMessage encrypted = encapsulationResult.getEncryptedMessage();
70 | System.out.println("Alice's shared secret: " + new String(Base64.encode(encapsulationResult.getSecret())));
71 |
72 | SidhPublicKey c0 = (SidhPublicKey) encrypted.getC0();
73 | byte[] c1 = encrypted.getC1();
74 | assertEquals("0FDEB26DBD96E0CD272283CA5BDD1435BC9A7F9AB7FC24F83CA926DEED038AE4E47F39F9886E0BD7EEBEAACD12AB435CC92AA3383B2C01E6B9E02BC3BEF9C6C2719014562A96A0F3E784E3FA44E5C62ED8CEA79E1108B6FECD5BF8836BF2DAE9FEB1863C4C8B3429220E2797F601FB4B8EBAFDD4F17355508D259CA60721D167F6E5480B5133E824F76D3240E97F31325DBB9A53E9A3EEE2E0712734825615A027857E2000D4D00E11988499A738452C93DA895BFA0E10294895CCF25E3C261CBE38F5D7E19ABE4E322094CB8DEC5BF7484902BABDE33CC69595F6013B20AABA9698C1DEA2BC6F65D57519294E6FEEA3B549599D480948374D2D21B643573C276E1A5B0745301F648D7982AB46A3065639960182BF365819EFC0D4E61E87D2820DBC0E849E99E875B21501D1CA7588A1D458CD70C7DF793D4993B9B1679886CAE8013A8DD854F010A100", c0.toOctetString());
75 | assertEquals("C9933FA642DC0AEA9985786ED36B98D3", OctetEncoding.toOctetString(c1, 16));
76 |
77 | byte[] secretDecaps = sike.decapsulate(keyPair.getPrivate(), keyPair.getPublic(), encrypted);
78 | System.out.println("Bob's shared secret: " + new String(Base64.encode(secretDecaps)));
79 | assertEquals("35F7F8FF388714DEDC41F139078CEDC9", OctetEncoding.toOctetString(secretDecaps, 16));
80 |
81 | boolean match = Arrays.equals(encapsulationResult.getSecret(), secretDecaps);
82 | System.out.println("Shared secrets match: " + match);
83 | assertTrue(match, "Decapsulation failed");
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/SikeRandomTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike;
18 |
19 | import com.wultra.security.pqc.sike.crypto.KeyGenerator;
20 | import com.wultra.security.pqc.sike.crypto.Sike;
21 | import com.wultra.security.pqc.sike.model.EncapsulationResult;
22 | import com.wultra.security.pqc.sike.model.EncryptedMessage;
23 | import com.wultra.security.pqc.sike.model.ImplementationType;
24 | import com.wultra.security.pqc.sike.model.Party;
25 | import com.wultra.security.pqc.sike.param.SikeParam;
26 | import com.wultra.security.pqc.sike.param.SikeParamP434;
27 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
28 | import org.bouncycastle.util.encoders.Base64;
29 | import org.junit.jupiter.api.Test;
30 |
31 | import java.security.GeneralSecurityException;
32 | import java.security.KeyPair;
33 | import java.security.Security;
34 | import java.util.Arrays;
35 |
36 | import static org.junit.jupiter.api.Assertions.assertTrue;
37 |
38 | /**
39 | * Test of SIKE key encapsulation.
40 | *
41 | * @author Roman Strobl, roman.strobl@wultra.com
42 | */
43 | class SikeRandomTest {
44 |
45 | private Sike sike;
46 | private SikeParam sikeParam;
47 | private KeyPair keyPair;
48 |
49 | static {
50 | Security.addProvider(new BouncyCastleProvider());
51 | }
52 |
53 | void initSike() throws GeneralSecurityException {
54 | sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
55 | KeyGenerator keyGenerator = new KeyGenerator(sikeParam);
56 | sike = new Sike(sikeParam);
57 | System.out.println("Prime: " + sikeParam.getPrime());
58 | // Enable key decapsulation
59 | keyPair = keyGenerator.generateKeyPair(Party.BOB);
60 | System.out.println("Bob's keypair:");
61 | System.out.println("Private key: " + keyPair.getPrivate());
62 | System.out.println("Public key: " + keyPair.getPublic());
63 | }
64 |
65 | @Test
66 | void testSikeEncryption() throws GeneralSecurityException {
67 | System.out.println("----------------------------------------");
68 | initSike();
69 | System.out.println("Testing SIKE encryption/decryption");
70 | byte[] message = "test123456789012".getBytes();
71 | System.out.println("Message to encrypt: " + new String(message));
72 | EncryptedMessage encrypted = sike.encrypt(keyPair.getPublic(), message);
73 | // Encrypted message is sent to Bob
74 | byte[] decrypted = sike.decrypt(keyPair.getPrivate(), encrypted);
75 | System.out.println("Decrypted message: " + new String(decrypted));
76 | boolean match = Arrays.equals(message, decrypted);
77 | System.out.println("Messages match: " + match);
78 | assertTrue(match, "Messages do not match");
79 | }
80 |
81 | @Test
82 | void testSikeEncapsulation() throws GeneralSecurityException {
83 | System.out.println("----------------------------------------");
84 | initSike();
85 | System.out.println("Testing SIKE encapsulation/decapsulation");
86 | EncapsulationResult encapsulationResult = sike.encapsulate(keyPair.getPublic());
87 | System.out.println("Alice's shared secret: " + new String(Base64.encode(encapsulationResult.getSecret())));
88 | // Encrypted message is sent to Bob
89 | EncryptedMessage encrypted = encapsulationResult.getEncryptedMessage();
90 | byte[] secretDecaps = sike.decapsulate(keyPair.getPrivate(), keyPair.getPublic(), encrypted);
91 | System.out.println("Bob's shared secret: " + new String(Base64.encode(secretDecaps)));
92 | boolean match = Arrays.equals(encapsulationResult.getSecret(), secretDecaps);
93 | System.out.println("Shared secrets match: " + match);
94 | assertTrue(match, "Decapsulation failed");
95 | }
96 |
97 | @Test
98 | void testSikeEncapsulationWithMessageTransport() throws GeneralSecurityException {
99 | System.out.println("----------------------------------------");
100 | initSike();
101 | System.out.println("Testing SIKE encapsulation/decapsulation with message transport");
102 | EncapsulationResult encapsulationResult = sike.encapsulate(keyPair.getPublic());
103 | System.out.println("Alice's shared secret: " + new String(Base64.encode(encapsulationResult.getSecret())));
104 | // Encrypted message is serialized, transported over the network and deserialized
105 | EncryptedMessage encrypted = encapsulationResult.getEncryptedMessage();
106 | byte[] encodedMessage = encrypted.getEncoded();
107 | EncryptedMessage transported = new EncryptedMessage(sikeParam, encodedMessage);
108 | byte[] secretDecaps = sike.decapsulate(keyPair.getPrivate(), keyPair.getPublic(), transported);
109 | System.out.println("Bob's shared secret: " + new String(Base64.encode(secretDecaps)));
110 | boolean match = Arrays.equals(encapsulationResult.getSecret(), secretDecaps);
111 | System.out.println("Shared secrets match: " + match);
112 | assertTrue(match, "Decapsulation failed");
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/kat/KatP434Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.kat;
18 |
19 | import com.wultra.security.pqc.sike.model.ImplementationType;
20 | import com.wultra.security.pqc.sike.param.SikeParam;
21 | import com.wultra.security.pqc.sike.param.SikeParamP434;
22 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
23 | import org.junit.jupiter.api.Test;
24 |
25 | import java.io.FileNotFoundException;
26 | import java.security.GeneralSecurityException;
27 | import java.security.Security;
28 |
29 | /**
30 | * Test of KAT responses for SIKEp434.
31 | */
32 | class KatP434Test {
33 |
34 | static {
35 | Security.addProvider(new BouncyCastleProvider());
36 | }
37 |
38 | @Test
39 | void testKatP434() throws FileNotFoundException, GeneralSecurityException {
40 | SikeParam sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
41 | KatTester.run(sikeParam, "kat/PQCkemKAT_374.rsp");
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/kat/KatP503Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.kat;
18 |
19 | import com.wultra.security.pqc.sike.model.ImplementationType;
20 | import com.wultra.security.pqc.sike.param.SikeParam;
21 | import com.wultra.security.pqc.sike.param.SikeParamP503;
22 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
23 | import org.junit.jupiter.api.Test;
24 |
25 | import java.io.FileNotFoundException;
26 | import java.security.GeneralSecurityException;
27 | import java.security.Security;
28 |
29 | /**
30 | * Test of KAT responses for SIKEp503.
31 | */
32 | class KatP503Test {
33 |
34 | static {
35 | Security.addProvider(new BouncyCastleProvider());
36 | }
37 |
38 | @Test
39 | void testKatP503() throws FileNotFoundException, GeneralSecurityException {
40 | SikeParam sikeParam = new SikeParamP503(ImplementationType.OPTIMIZED);
41 | KatTester.run(sikeParam, "kat/PQCkemKAT_434.rsp");
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/kat/KatP610Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.kat;
18 |
19 | import com.wultra.security.pqc.sike.model.ImplementationType;
20 | import com.wultra.security.pqc.sike.param.SikeParam;
21 | import com.wultra.security.pqc.sike.param.SikeParamP610;
22 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
23 | import org.junit.jupiter.api.Test;
24 |
25 | import java.io.FileNotFoundException;
26 | import java.security.GeneralSecurityException;
27 | import java.security.Security;
28 |
29 | /**
30 | * Test of KAT responses for SIKEp610.
31 | */
32 | class KatP610Test {
33 |
34 | static {
35 | Security.addProvider(new BouncyCastleProvider());
36 | }
37 |
38 | @Test
39 | void testKatP610() throws FileNotFoundException, GeneralSecurityException {
40 | SikeParam sikeParam = new SikeParamP610(ImplementationType.OPTIMIZED);
41 | KatTester.run(sikeParam, "kat/PQCkemKAT_524.rsp");
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/kat/KatP751Test.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.kat;
18 |
19 | import com.wultra.security.pqc.sike.model.ImplementationType;
20 | import com.wultra.security.pqc.sike.param.SikeParam;
21 | import com.wultra.security.pqc.sike.param.SikeParamP751;
22 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
23 | import org.junit.jupiter.api.Test;
24 |
25 | import java.io.FileNotFoundException;
26 | import java.security.GeneralSecurityException;
27 | import java.security.Security;
28 |
29 | /**
30 | * Test of KAT responses for SIKEp710.
31 | */
32 | class KatP751Test {
33 |
34 | static {
35 | Security.addProvider(new BouncyCastleProvider());
36 | }
37 |
38 | @Test
39 | void testKatP710() throws FileNotFoundException, GeneralSecurityException {
40 | SikeParam sikeParam = new SikeParamP751(ImplementationType.OPTIMIZED);
41 | KatTester.run(sikeParam, "kat/PQCkemKAT_644.rsp");
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/kat/KatTester.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.kat;
18 |
19 | import com.wultra.security.pqc.sike.crypto.KeyGenerator;
20 | import com.wultra.security.pqc.sike.crypto.RandomGenerator;
21 | import com.wultra.security.pqc.sike.crypto.Sike;
22 | import com.wultra.security.pqc.sike.kat.model.KatRspFile;
23 | import com.wultra.security.pqc.sike.kat.model.KatRspRecord;
24 | import com.wultra.security.pqc.sike.kat.util.CrtDrbgRandom;
25 | import com.wultra.security.pqc.sike.model.*;
26 | import com.wultra.security.pqc.sike.param.SikeParam;
27 | import com.wultra.security.pqc.sike.util.OctetEncoding;
28 | import org.bouncycastle.util.encoders.Hex;
29 |
30 | import java.io.File;
31 | import java.io.FileNotFoundException;
32 | import java.net.URL;
33 | import java.security.GeneralSecurityException;
34 | import java.security.KeyPair;
35 | import java.util.Arrays;
36 | import java.util.List;
37 |
38 | import static org.junit.jupiter.api.Assertions.*;
39 |
40 | /**
41 | * Universal KAT tester.
42 | */
43 | public class KatTester {
44 |
45 | public static void run(SikeParam sikeParam, String katFileName) throws FileNotFoundException, GeneralSecurityException {
46 | String runAllKatTests = System.getProperty("runAllKatTests");
47 | boolean runAllTests = false;
48 | if ("true".equals(runAllKatTests)) {
49 | runAllTests = true;
50 | }
51 | System.out.println("----------------------------------------");
52 | System.out.println("KAT tests for " + sikeParam.getName());
53 | ClassLoader classLoader = KatTester.class.getClassLoader();
54 | URL fileName = classLoader.getResource(katFileName);
55 | assertNotNull(fileName);
56 | File file = new File(fileName.getFile());
57 | KatRspFile katFile = new KatRspFile(file);
58 | List katRecords = katFile.getKatRecords();
59 |
60 | System.out.println("Prime: " + sikeParam.getPrime());
61 |
62 | for (KatRspRecord kat: katRecords) {
63 | if (!runAllTests && kat.getCount() > 9) {
64 | System.out.println("Additional tests were skipped, use -DrunAllKatTests=true to run all KAT tests");
65 | break;
66 | }
67 | System.out.println("Record: " + kat.getCount());
68 | byte[] seedBytes = Hex.decode(kat.getSeed());
69 | CrtDrbgRandom drbgRandom = new CrtDrbgRandom(seedBytes);
70 | KeyGenerator keyGenerator = new KeyGenerator(sikeParam, new RandomGenerator(drbgRandom));
71 | KeyPair keyPair = keyGenerator.generateKeyPair(Party.BOB);
72 | SidhPrivateKey priv = (SidhPrivateKey) keyPair.getPrivate();
73 | SidhPublicKey pub = (SidhPublicKey) keyPair.getPublic();
74 | assertEquals(kat.getSk(), priv.toOctetString() + pub.toOctetString());
75 | assertEquals(kat.getPk(), pub.toOctetString());
76 |
77 | Sike sike = new Sike(sikeParam, drbgRandom);
78 | EncapsulationResult encapsulationResult = sike.encapsulate(keyPair.getPublic());
79 | EncryptedMessage encrypted = encapsulationResult.getEncryptedMessage();
80 | SidhPublicKey c0 = (SidhPublicKey) encrypted.getC0();
81 | String ssA = OctetEncoding.toOctetString(encapsulationResult.getSecret(), sikeParam.getMessageBytes());
82 | System.out.println("Alice's shared secret: " + ssA);
83 | byte[] c1 = encrypted.getC1();
84 | assertEquals(kat.getCt(), c0.toOctetString() + OctetEncoding.toOctetString(c1, sikeParam.getMessageBytes()));
85 |
86 | byte[] secretDecaps = sike.decapsulate(keyPair.getPrivate(), keyPair.getPublic(), encrypted);
87 | String ssB = OctetEncoding.toOctetString(secretDecaps, sikeParam.getMessageBytes());
88 | System.out.println("Bob's shared secret: " + ssB);
89 | assertEquals(kat.getSs(), ssB);
90 |
91 | boolean match = Arrays.equals(encapsulationResult.getSecret(), secretDecaps);
92 | System.out.println("Shared secrets match: " + match);
93 | assertTrue(match, "Decapsulation failed");
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/kat/model/KatRspFile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.kat.model;
18 |
19 | import java.io.File;
20 | import java.io.FileNotFoundException;
21 | import java.util.ArrayList;
22 | import java.util.List;
23 | import java.util.Scanner;
24 |
25 | /**
26 | * Class representing a KAT response file.
27 | *
28 | * @author Roman Strobl, roman.strobl@wultra.com
29 | */
30 | public class KatRspFile {
31 |
32 | private final List katRecords = new ArrayList<>();
33 |
34 | /**
35 | * KAT file constructor.
36 | * @param file File to read.
37 | */
38 | public KatRspFile(File file) throws FileNotFoundException {
39 | readFile(file);
40 | }
41 |
42 | /**
43 | * Get parsed KAT records.
44 | * @return KAT records.
45 | */
46 | public List getKatRecords() {
47 | return katRecords;
48 | }
49 |
50 | /**
51 | * Add a KAT record.
52 | * @param katRecord KAT record.
53 | */
54 | public void add(KatRspRecord katRecord) {
55 | katRecords.add(katRecord);
56 | }
57 |
58 | /**
59 | * Read the KAT response file.
60 | * @throws FileNotFoundException Thrown when file is not found.
61 | */
62 | private void readFile(File file) throws FileNotFoundException {
63 | Scanner scanner = new Scanner(file);
64 | KatRspRecord record = new KatRspRecord();
65 | while (scanner.hasNextLine()) {
66 | String line = scanner.nextLine();
67 | if (!line.contains(" = ")) {
68 | continue;
69 | }
70 | String[] parts = line.split(" = ");
71 | if (parts.length != 2) {
72 | continue;
73 | }
74 | String key = parts[0];
75 | String value = parts[1];
76 | switch(key) {
77 | case "count":
78 | record = new KatRspRecord();
79 | record.setCount(Integer.parseInt(value));
80 | break;
81 | case "seed":
82 | record.setSeed(value);
83 | break;
84 | case "pk":
85 | record.setPk(value);
86 | break;
87 | case "sk":
88 | record.setSk(value);
89 | break;
90 | case "ct":
91 | record.setCt(value);
92 | break;
93 | case "ss":
94 | record.setSs(value);
95 | add(record);
96 | break;
97 | }
98 | }
99 | }
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/kat/model/KatRspRecord.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.kat.model;
18 |
19 | import java.util.Objects;
20 |
21 | /**
22 | * Class representing a KAT response record.
23 | *
24 | * @author Roman Strobl, roman.strobl@wultra.com
25 | */
26 | public class KatRspRecord {
27 |
28 | private int count;
29 | private String seed;
30 | private String pk;
31 | private String sk;
32 | private String ct;
33 | private String ss;
34 |
35 | /**
36 | * Default constructor.
37 | */
38 | public KatRspRecord() {
39 | }
40 |
41 | /**
42 | * Constructor with all details.
43 | * @param count Counter.
44 | * @param seed Seed.
45 | * @param pk Public key.
46 | * @param sk Private key.
47 | * @param ct Encrypted message.
48 | * @param ss Shared secret.
49 | */
50 | public KatRspRecord(int count, String seed, String pk, String sk, String ct, String ss) {
51 | this.count = count;
52 | this.seed = seed;
53 | this.pk = pk;
54 | this.sk = sk;
55 | this.ct = ct;
56 | this.ss = ss;
57 | }
58 |
59 | /**
60 | * Get the counter.
61 | * @return Counter.
62 | */
63 | public int getCount() {
64 | return count;
65 | }
66 |
67 | /**
68 | * Set the counter.
69 | * @param count Counter.
70 | */
71 | public void setCount(int count) {
72 | this.count = count;
73 | }
74 |
75 | /**
76 | * Get the seed.
77 | * @return Seed.
78 | */
79 | public String getSeed() {
80 | return seed;
81 | }
82 |
83 | /**
84 | * Set the seed.
85 | * @param seed Seed.
86 | */
87 | public void setSeed(String seed) {
88 | this.seed = seed;
89 | }
90 |
91 | /**
92 | * Get the public key.
93 | * @return Public key.
94 | */
95 | public String getPk() {
96 | return pk;
97 | }
98 |
99 | /**
100 | * Set the public key.
101 | * @param pk Public key.
102 | */
103 | public void setPk(String pk) {
104 | this.pk = pk;
105 | }
106 |
107 | /**
108 | * Get the private key.
109 | * @return Private key.
110 | */
111 | public String getSk() {
112 | return sk;
113 | }
114 |
115 | /**
116 | * Set the private key.
117 | * @param sk Private key.
118 | */
119 | public void setSk(String sk) {
120 | this.sk = sk;
121 | }
122 |
123 | /**
124 | * Get the encrypted message.
125 | * @return Encrypted message.
126 | */
127 | public String getCt() {
128 | return ct;
129 | }
130 |
131 | /**
132 | * Set the encrypted message.
133 | * @param ct Encrypted message.
134 | */
135 | public void setCt(String ct) {
136 | this.ct = ct;
137 | }
138 |
139 | /**
140 | * Get the shared secret.
141 | * @return Shared secret.
142 | */
143 | public String getSs() {
144 | return ss;
145 | }
146 |
147 | /**
148 | * Set the shared secret.
149 | * @param ss Shared secret.
150 | */
151 | public void setSs(String ss) {
152 | this.ss = ss;
153 | }
154 |
155 | @Override
156 | public boolean equals(Object o) {
157 | if (this == o) return true;
158 | if (o == null || getClass() != o.getClass()) return false;
159 | KatRspRecord katRecord = (KatRspRecord) o;
160 | return seed.equals(katRecord.seed) &&
161 | pk.equals(katRecord.pk) &&
162 | ct.equals(katRecord.ct) &&
163 | ss.equals(katRecord.ss);
164 | }
165 |
166 | @Override
167 | public int hashCode() {
168 | return Objects.hash(seed, pk, ct, ss);
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/kat/util/CrtDrbgRandom.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.kat.util;
18 |
19 | import javax.crypto.Cipher;
20 | import javax.crypto.spec.SecretKeySpec;
21 | import java.security.GeneralSecurityException;
22 | import java.security.SecureRandom;
23 |
24 | /**
25 | * A simple SP800-90A based CTR DRBG SecureRandom with fixed parameters and without DF.
26 | *
27 | * This random generator is not secure and is only used for deterministic generation of cryptographic material
28 | * used for KAT tests.
29 | *
30 | * @author Roman Strobl, roman.strobl@wultra.com
31 | */
32 | public class CrtDrbgRandom extends SecureRandom {
33 |
34 | private static final int KEY_SIZE = 32;
35 | private static final int VALUE_SIZE = 16;
36 | private static final int SEED_SIZE = KEY_SIZE + VALUE_SIZE;
37 |
38 | private final Cipher cipher;
39 | private byte[] key;
40 | private byte[] value;
41 |
42 | /**
43 | * CTR DRBG SecureRandom constructor.
44 | * @param seed Seed for deterministic random generation.
45 | * @throws GeneralSecurityException Throw in case encryption fails.
46 | */
47 | public CrtDrbgRandom(byte[] seed) throws GeneralSecurityException {
48 | cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC");
49 | ctrDrbgInstantiateAlgorithm(seed);
50 | }
51 |
52 | /**
53 | * Generate random bytes.
54 | * @param bytes Byte array to fill with random bytes.
55 | */
56 | public void nextBytes(byte[] bytes) {
57 | synchronized (this) {
58 | try {
59 | generate(bytes);
60 | } catch (GeneralSecurityException e) {
61 | // Ignored, AES algorithm is available in case this class was successfully constructed
62 | }
63 | }
64 | }
65 |
66 | /**
67 | * Instantiate CTR DRBG algorithm without derivation function.
68 | * @param seed Seed for deterministic random generation.
69 | * @throws GeneralSecurityException Throw in case encryption fails.
70 | */
71 | private void ctrDrbgInstantiateAlgorithm(byte[] seed) throws GeneralSecurityException {
72 | key = new byte[KEY_SIZE];
73 | value = new byte[VALUE_SIZE];
74 | ctrDrbgUpdate(seed);
75 | }
76 |
77 | /**
78 | * Generate random bytes.
79 | * @param output Output byte array.
80 | * @throws GeneralSecurityException Throw in case encryption fails.
81 | */
82 | private void generate(byte[] output) throws GeneralSecurityException {
83 | byte[] val = new byte[VALUE_SIZE];
84 | cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
85 |
86 | for (int i = 0; i <= output.length / val.length; i++) {
87 | int bytesToCopy = Math.min((output.length - i * VALUE_SIZE), VALUE_SIZE);
88 |
89 | if (bytesToCopy != 0) {
90 | addOne(value);
91 | cipher.doFinal(value, 0, value.length, val);
92 | System.arraycopy(val, 0, output, i * val.length, bytesToCopy);
93 | }
94 | }
95 |
96 | ctrDrbgUpdate(null);
97 |
98 | }
99 |
100 | /**
101 | * Update CTR DRBG state.
102 | * @param data Input data.
103 | * @throws GeneralSecurityException Thrown in case encryption fails.
104 | */
105 | private void ctrDrbgUpdate(byte[] data) throws GeneralSecurityException {
106 | byte[] temp = new byte[SEED_SIZE];
107 | byte[] outputBlock = new byte[cipher.getBlockSize()];
108 | int i = 0;
109 | int outLen = cipher.getBlockSize();
110 |
111 | cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
112 |
113 | while (i * outLen < SEED_SIZE) {
114 | addOne(value);
115 | cipher.doFinal(value, 0, 16, outputBlock);
116 | int bytesToCopy = Math.min((temp.length - i * outLen), outLen);
117 | System.arraycopy(outputBlock, 0, temp, i * outLen, bytesToCopy);
118 | i++;
119 | }
120 |
121 | if (data != null) {
122 | temp = xor(data, temp);
123 | }
124 |
125 | System.arraycopy(temp, 0, key, 0, KEY_SIZE);
126 | System.arraycopy(temp, KEY_SIZE, value, 0, VALUE_SIZE);
127 | }
128 |
129 | /**
130 | * Add number one to a byte array.
131 | * @param bytes Byte array to update.
132 | */
133 | private void addOne(byte[] bytes) {
134 | int carry = 1;
135 | for (int i = 1; i <= bytes.length; i++) {
136 | int res = (bytes[bytes.length - i] & 0xff) + carry;
137 | carry = (res > 0xff) ? 1 : 0;
138 | bytes[bytes.length - i] = (byte) res;
139 | }
140 | }
141 |
142 | /**
143 | * XOR two byte arrays.
144 | * @param a First byte array.
145 | * @param b Second byte array.
146 | * @return Byte array with result.
147 | */
148 | private byte[] xor(byte[] a, byte[] b) {
149 | byte[] result = new byte[SEED_SIZE];
150 | for (int i = 0; i < SEED_SIZE; i++) {
151 | result[i] = (byte) (a[i] ^ b[i]);
152 | }
153 | return result;
154 | }
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/math/Fp2MathTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math;
18 |
19 | import com.wultra.security.pqc.sike.math.api.Fp2Element;
20 | import com.wultra.security.pqc.sike.math.api.FpElement;
21 | import com.wultra.security.pqc.sike.math.optimized.fp.Fp2ElementOpti;
22 | import com.wultra.security.pqc.sike.math.optimized.fp.FpElementOpti;
23 | import com.wultra.security.pqc.sike.model.ImplementationType;
24 | import com.wultra.security.pqc.sike.param.SikeParam;
25 | import com.wultra.security.pqc.sike.param.SikeParamP434;
26 | import org.junit.jupiter.api.Test;
27 |
28 | import static org.junit.jupiter.api.Assertions.assertEquals;
29 |
30 | /**
31 | * Test of Fp2Element mathematics.
32 | *
33 | * @author Roman Strobl, roman.strobl@wultra.com
34 | */
35 | class Fp2MathTest {
36 |
37 | private final SikeParam sikeParam = new SikeParamP434(ImplementationType.OPTIMIZED);
38 |
39 | @Test
40 | void testAddZero() {
41 | FpElement x = new FpElementOpti(sikeParam);
42 | Fp2Element x2 = new Fp2ElementOpti(sikeParam, x, x);
43 | Fp2Element result = x2.add(x2);
44 | assertEquals(x2, result);
45 | }
46 |
47 | @Test
48 | void testAddOneAndOne() {
49 | FpElementOpti x = new FpElementOpti(sikeParam);
50 | x.getValue()[x.size() - 1] = 1L;
51 | Fp2Element x2 = new Fp2ElementOpti(sikeParam, x, x);
52 | Fp2Element result = x2.add(x2);
53 | FpElementOpti expected = new FpElementOpti(sikeParam);
54 | expected.getValue()[expected.size() - 1] = 2L;
55 | Fp2Element expected2 = new Fp2ElementOpti(sikeParam, expected, expected);
56 | assertEquals(expected2, result);
57 | }
58 |
59 | @Test
60 | void testSubZero() {
61 | FpElement x = new FpElementOpti(sikeParam);
62 | Fp2Element x2 = new Fp2ElementOpti(sikeParam, x, x);
63 | Fp2Element result = x2.subtract(x2);
64 | assertEquals(x2, result);
65 | }
66 |
67 | // TODO more Fp2Element math tests
68 | }
69 |
--------------------------------------------------------------------------------
/sike-java/src/test/java/com/wultra/security/pqc/sike/math/UnsignedLongTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Wultra s.r.o.
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU Affero General Public License as published
6 | * by the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU Affero General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU Affero General Public License
15 | * along with this program. If not, see .
16 | */
17 | package com.wultra.security.pqc.sike.math;
18 |
19 | import com.wultra.security.pqc.sike.math.optimized.fp.UnsignedLong;
20 | import org.junit.jupiter.api.Test;
21 |
22 | import static org.junit.jupiter.api.Assertions.assertEquals;
23 |
24 | /**
25 | * Test of unsigned 64-bit integer arithmetic.
26 | *
27 | * @author Roman Strobl, roman.strobl@wultra.com
28 | */
29 | class UnsignedLongTest {
30 |
31 | @Test
32 | void testZeroAdd() {
33 | long x = 0L;
34 | long y = 0L;
35 | long carry = 0L;
36 | long[] result = UnsignedLong.add(x, y, carry);
37 | assertEquals(0L, result[0]);
38 | assertEquals(0L, result[1]);
39 | }
40 |
41 | @Test
42 | void testZeroOneAdd() {
43 | long x = 0L;
44 | long y = 1L;
45 | long carry = 0L;
46 | long[] result = UnsignedLong.add(x, y, carry);
47 | assertEquals(1L, result[0]);
48 | assertEquals(0L, result[1]);
49 | }
50 |
51 | @Test
52 | void testZeroOneAddAndCarry() {
53 | long x = 0L;
54 | long y = 1L;
55 | long carry = 1L;
56 | long[] result = UnsignedLong.add(x, y, carry);
57 | assertEquals(2L, result[0]);
58 | assertEquals(0L, result[1]);
59 | }
60 |
61 | @Test
62 | void testMaxValueAddZero() {
63 | long x = Long.parseUnsignedLong("18446744073709551615");
64 | long y = 0L;
65 | long carry = 0L;
66 | long[] result = UnsignedLong.add(x, y, carry);
67 | assertEquals(Long.parseUnsignedLong("18446744073709551615"), result[0]);
68 | assertEquals(0L, result[1]);
69 | }
70 |
71 | @Test
72 | void testMaxValueAddOne() {
73 | long x = Long.parseUnsignedLong("18446744073709551615");
74 | long y = 1L;
75 | long carry = 0L;
76 | long[] result = UnsignedLong.add(x, y, carry);
77 | assertEquals(0L, result[0]);
78 | assertEquals(1L, result[1]);
79 | }
80 |
81 | @Test
82 | void testMaxValueAddTwo() {
83 | long x = Long.parseUnsignedLong("18446744073709551615");
84 | long y = 2L;
85 | long carry = 0L;
86 | long[] result = UnsignedLong.add(x, y, carry);
87 | assertEquals(1L, result[0]);
88 | assertEquals(1L, result[1]);
89 | }
90 |
91 | @Test
92 | void testMaxValueAddZeroAndCarry() {
93 | long x = Long.parseUnsignedLong("18446744073709551615");
94 | long y = 0L;
95 | long carry = 1L;
96 | long[] result = UnsignedLong.add(x, y, carry);
97 | assertEquals(0L, result[0]);
98 | assertEquals(1L, result[1]);
99 | }
100 |
101 | @Test
102 | void testMaxValueAddOneAndCarry() {
103 | long x = Long.parseUnsignedLong("18446744073709551615");
104 | long y = 1L;
105 | long carry = 1L;
106 | long[] result = UnsignedLong.add(x, y, carry);
107 | assertEquals(1L, result[0]);
108 | assertEquals(1L, result[1]);
109 | }
110 |
111 | @Test
112 | void testMaxValueMinusOneAddZeroAndCarry() {
113 | long x = Long.parseUnsignedLong("18446744073709551614");
114 | long y = 0L;
115 | long carry = 1L;
116 | long[] result = UnsignedLong.add(x, y, carry);
117 | assertEquals(Long.parseUnsignedLong("18446744073709551615"), result[0]);
118 | assertEquals(0L, result[1]);
119 | }
120 |
121 | @Test
122 | void testZeroSub() {
123 | long x = 0L;
124 | long y = 0L;
125 | long borrow = 0L;
126 | long[] result = UnsignedLong.sub(x, y, borrow);
127 | assertEquals(0L, result[0]);
128 | assertEquals(0L, result[1]);
129 | }
130 |
131 | @Test
132 | void testOneZeroSub() {
133 | long x = 1L;
134 | long y = 0L;
135 | long borrow = 0L;
136 | long[] result = UnsignedLong.sub(x, y, borrow);
137 | assertEquals(1L, result[0]);
138 | assertEquals(0L, result[1]);
139 | }
140 |
141 | @Test
142 | void testOneZeroSubBorrow() {
143 | long x = 1L;
144 | long y = 0L;
145 | long borrow = 1L;
146 | long[] result = UnsignedLong.sub(x, y, borrow);
147 | assertEquals(0L, result[0]);
148 | assertEquals(0L, result[1]);
149 | }
150 |
151 | @Test
152 | void testZeroSubOne() {
153 | long x = 0L;
154 | long y = 1L;
155 | long borrow = 0L;
156 | long[] result = UnsignedLong.sub(x, y, borrow);
157 | assertEquals(Long.parseUnsignedLong("18446744073709551615"), result[0]);
158 | assertEquals(1L, result[1]);
159 | }
160 |
161 | @Test
162 | void testZeroSubZeroBorrow() {
163 | long x = 0L;
164 | long y = 0L;
165 | long borrow = 1L;
166 | long[] result = UnsignedLong.sub(x, y, borrow);
167 | assertEquals(Long.parseUnsignedLong("18446744073709551615"), result[0]);
168 | assertEquals(1L, result[1]);
169 | }
170 |
171 | @Test
172 | void testZeroSubOneBorrow() {
173 | long x = 0L;
174 | long y = 1L;
175 | long borrow = 1L;
176 | long[] result = UnsignedLong.sub(x, y, borrow);
177 | assertEquals(Long.parseUnsignedLong("18446744073709551614"), result[0]);
178 | assertEquals(1L, result[1]);
179 | }
180 |
181 | @Test
182 | void testMaxSubMax() {
183 | long x = Long.parseUnsignedLong("18446744073709551615");
184 | long y = Long.parseUnsignedLong("18446744073709551615");
185 | long borrow = 0L;
186 | long[] result = UnsignedLong.sub(x, y, borrow);
187 | assertEquals(0L, result[0]);
188 | assertEquals(0L, result[1]);
189 | }
190 |
191 | @Test
192 | void testMaxSubMaxMinusOneBorrow() {
193 | long x = Long.parseUnsignedLong("18446744073709551615");
194 | long y = Long.parseUnsignedLong("18446744073709551614");
195 | long borrow = 1L;
196 | long[] result = UnsignedLong.sub(x, y, borrow);
197 | assertEquals(0L, result[0]);
198 | assertEquals(0L, result[1]);
199 | }
200 |
201 | @Test
202 | void testMultiplyZeroByZero() {
203 | long x = 0L;
204 | long y = 0L;
205 | long[] result = UnsignedLong.mul(x, y);
206 | assertEquals(0L, result[0]);
207 | assertEquals(0L, result[1]);
208 | }
209 |
210 | @Test
211 | void testMultiplyOneByOne() {
212 | long x = 1L;
213 | long y = 1L;
214 | long[] result = UnsignedLong.mul(x, y);
215 | assertEquals(0L, result[0]);
216 | assertEquals(1L, result[1]);
217 | }
218 |
219 | @Test
220 | void testMultiplyBigValueByTwo() {
221 | long x = Long.parseUnsignedLong("9223372036854775807");
222 | long y = 2L;
223 | long[] result = UnsignedLong.mul(x, y);
224 | assertEquals(0L, result[0]);
225 | assertEquals(Long.parseUnsignedLong("18446744073709551614"), result[1]);
226 | }
227 |
228 | @Test
229 | void testMultiplyMaxByMax() {
230 | long x = Long.parseUnsignedLong("18446744073709551615");
231 | long y = Long.parseUnsignedLong("18446744073709551615");
232 | long[] result = UnsignedLong.mul(x, y);
233 | // ((2^64)-1)*((2^64)-1) / (2^64) = 18446744073709551614
234 | assertEquals(Long.parseUnsignedLong("18446744073709551614"), result[0]);
235 | // ((2^64)-1)*((2^64)-1) mod 2^64 = 1
236 | assertEquals(1L, result[1]);
237 | }
238 |
239 | @Test
240 | void testMultiplyHiLo1() {
241 | long x = Long.parseUnsignedLong("123456789123456789");
242 | long y = Long.parseUnsignedLong("987654321987654321");
243 | long[] result = UnsignedLong.mul(x, y);
244 | assertEquals(Long.parseUnsignedLong("6609981190679600"), result[0]);
245 | assertEquals(Long.parseUnsignedLong("14369616054794401669"), result[1]);
246 | }
247 |
248 | @Test
249 | void testMultiplyHiLo2() {
250 | long x = Long.parseUnsignedLong("11111111111");
251 | long y = Long.parseUnsignedLong("99999999999");
252 | long[] result = UnsignedLong.mul(x, y);
253 | assertEquals(Long.parseUnsignedLong("60"), result[0]);
254 | assertEquals(Long.parseUnsignedLong("4306466666315791929"), result[1]);
255 | }
256 |
257 | @Test
258 | void testMultiplyHiLo3() {
259 | long x = Long.parseUnsignedLong("555555555");
260 | long y = Long.parseUnsignedLong("555555555");
261 | long[] result = UnsignedLong.mul(x, y);
262 | assertEquals(0L, result[0]);
263 | assertEquals(Long.parseUnsignedLong("308641974691358025"), result[1]);
264 | }
265 |
266 | }
267 |
--------------------------------------------------------------------------------