aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/prov/src/main/java/org/spongycastle/pqc/jcajce/provider/mceliece/McElieceCCA2Primitives.java
blob: a63c1852dd50ced7f232a347ea7ee9b14a78878c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package org.spongycastle.pqc.jcajce.provider.mceliece;

import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PrivateKeyParameters;
import org.spongycastle.pqc.crypto.mceliece.McElieceCCA2PublicKeyParameters;
import org.spongycastle.pqc.math.linearalgebra.GF2Matrix;
import org.spongycastle.pqc.math.linearalgebra.GF2Vector;
import org.spongycastle.pqc.math.linearalgebra.GF2mField;
import org.spongycastle.pqc.math.linearalgebra.GoppaCode;
import org.spongycastle.pqc.math.linearalgebra.Permutation;
import org.spongycastle.pqc.math.linearalgebra.PolynomialGF2mSmallM;
import org.spongycastle.pqc.math.linearalgebra.Vector;

/**
 * Core operations for the CCA-secure variants of McEliece.
 */
public final class McElieceCCA2Primitives
{

    /**
     * Default constructor (private).
     */
    private McElieceCCA2Primitives()
    {
    }

    /**
     * The McEliece encryption primitive.
     *
     * @param pubKey the public key
     * @param m      the message vector
     * @param z      the error vector
     * @return <tt>m*G + z</tt>
     */
    public static GF2Vector encryptionPrimitive(BCMcElieceCCA2PublicKey pubKey,
                                                GF2Vector m, GF2Vector z)
    {

        GF2Matrix matrixG = pubKey.getG();
        Vector mG = matrixG.leftMultiplyLeftCompactForm(m);
        return (GF2Vector)mG.add(z);
    }

    public static GF2Vector encryptionPrimitive(McElieceCCA2PublicKeyParameters pubKey,
                                                GF2Vector m, GF2Vector z)
    {

        GF2Matrix matrixG = pubKey.getMatrixG();
        Vector mG = matrixG.leftMultiplyLeftCompactForm(m);
        return (GF2Vector)mG.add(z);
    }

    /**
     * The McEliece decryption primitive.
     *
     * @param privKey the private key
     * @param c       the ciphertext vector <tt>c = m*G + z</tt>
     * @return the message vector <tt>m</tt> and the error vector <tt>z</tt>
     */
    public static GF2Vector[] decryptionPrimitive(
        BCMcElieceCCA2PrivateKey privKey, GF2Vector c)
    {

        // obtain values from private key
        int k = privKey.getK();
        Permutation p = privKey.getP();
        GF2mField field = privKey.getField();
        PolynomialGF2mSmallM gp = privKey.getGoppaPoly();
        GF2Matrix h = privKey.getH();
        PolynomialGF2mSmallM[] q = privKey.getQInv();

        // compute inverse permutation P^-1
        Permutation pInv = p.computeInverse();

        // multiply c with permutation P^-1
        GF2Vector cPInv = (GF2Vector)c.multiply(pInv);

        // compute syndrome of cP^-1
        GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv);

        // decode syndrome
        GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q);
        GF2Vector mG = (GF2Vector)cPInv.add(errors);

        // multiply codeword and error vector with P
        mG = (GF2Vector)mG.multiply(p);
        errors = (GF2Vector)errors.multiply(p);

        // extract plaintext vector (last k columns of mG)
        GF2Vector m = mG.extractRightVector(k);

        // return vectors
        return new GF2Vector[]{m, errors};
    }

    public static GF2Vector[] decryptionPrimitive(
        McElieceCCA2PrivateKeyParameters privKey, GF2Vector c)
    {

        // obtain values from private key
        int k = privKey.getK();
        Permutation p = privKey.getP();
        GF2mField field = privKey.getField();
        PolynomialGF2mSmallM gp = privKey.getGoppaPoly();
        GF2Matrix h = privKey.getH();
        PolynomialGF2mSmallM[] q = privKey.getQInv();

        // compute inverse permutation P^-1
        Permutation pInv = p.computeInverse();

        // multiply c with permutation P^-1
        GF2Vector cPInv = (GF2Vector)c.multiply(pInv);

        // compute syndrome of cP^-1
        GF2Vector syndVec = (GF2Vector)h.rightMultiply(cPInv);

        // decode syndrome
        GF2Vector errors = GoppaCode.syndromeDecode(syndVec, field, gp, q);
        GF2Vector mG = (GF2Vector)cPInv.add(errors);

        // multiply codeword and error vector with P
        mG = (GF2Vector)mG.multiply(p);
        errors = (GF2Vector)errors.multiply(p);

        // extract plaintext vector (last k columns of mG)
        GF2Vector m = mG.extractRightVector(k);

        // return vectors
        return new GF2Vector[]{m, errors};
    }

}