1 package org.bouncycastle.pqc.crypto.rainbow;
2 
3 import java.security.SecureRandom;
4 
5 import org.bouncycastle.crypto.CipherParameters;
6 import org.bouncycastle.crypto.CryptoServicesRegistrar;
7 import org.bouncycastle.crypto.params.ParametersWithRandom;
8 import org.bouncycastle.pqc.crypto.MessageSigner;
9 import org.bouncycastle.pqc.crypto.rainbow.util.ComputeInField;
10 import org.bouncycastle.pqc.crypto.rainbow.util.GF2Field;
11 
12 /**
13  * It implements the sign and verify functions for the Rainbow Signature Scheme.
14  * Here the message, which has to be signed, is updated. The use of
15  * different hash functions is possible.
16  * <p>
17  * Detailed information about the signature and the verify-method is to be found
18  * in the paper of Jintai Ding, Dieter Schmidt: Rainbow, a New Multivariable
19  * Polynomial Signature Scheme. ACNS 2005: 164-175
20  * (https://dx.doi.org/10.1007/11496137_12)
21  */
22 public class RainbowSigner
23     implements MessageSigner
24 {
25     private static final int MAXITS = 65536;
26 
27     // Source of randomness
28     private SecureRandom random;
29 
30     // The length of a document that can be signed with the privKey
31     int signableDocumentLength;
32 
33     // Container for the oil and vinegar variables of all the layers
34     private short[] x;
35 
36     private ComputeInField cf = new ComputeInField();
37 
38     RainbowKeyParameters key;
39 
init(boolean forSigning, CipherParameters param)40     public void init(boolean forSigning,
41                      CipherParameters param)
42     {
43         if (forSigning)
44         {
45             if (param instanceof ParametersWithRandom)
46             {
47                 ParametersWithRandom rParam = (ParametersWithRandom)param;
48 
49                 this.random = rParam.getRandom();
50                 this.key = (RainbowPrivateKeyParameters)rParam.getParameters();
51 
52             }
53             else
54             {
55 
56                 this.random = CryptoServicesRegistrar.getSecureRandom();
57                 this.key = (RainbowPrivateKeyParameters)param;
58             }
59         }
60         else
61         {
62             this.key = (RainbowPublicKeyParameters)param;
63         }
64 
65         this.signableDocumentLength = this.key.getDocLength();
66     }
67 
68 
69     /**
70      * initial operations before solving the Linear equation system.
71      *
72      * @param layer the current layer for which a LES is to be solved.
73      * @param msg   the message that should be signed.
74      * @return Y_ the modified document needed for solving LES, (Y_ =
75      * A1^{-1}*(Y-b1)) linear map L1 = A1 x + b1.
76      */
initSign(Layer[] layer, short[] msg)77     private short[] initSign(Layer[] layer, short[] msg)
78     {
79 
80         /* preparation: Modifies the document with the inverse of L1 */
81         // tmp = Y - b1:
82         short[] tmpVec = new short[msg.length];
83 
84         tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB1(), msg);
85 
86         // Y_ = A1^{-1} * (Y - b1) :
87         short[] Y_ = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA1(), tmpVec);
88 
89         /* generates the vinegar vars of the first layer at random */
90         for (int i = 0; i < layer[0].getVi(); i++)
91         {
92             x[i] = (short)random.nextInt();
93             x[i] = (short)(x[i] & GF2Field.MASK);
94         }
95 
96         return Y_;
97     }
98 
99     /**
100      * This function signs the message that has been updated, making use of the
101      * private key.
102      * <p>
103      * For computing the signature, L1 and L2 are needed, as well as LES should
104      * be solved for each layer in order to find the Oil-variables in the layer.
105      * <p>
106      * The Vinegar-variables of the first layer are random generated.
107      *
108      * @param message the message
109      * @return the signature of the message.
110      */
generateSignature(byte[] message)111     public byte[] generateSignature(byte[] message)
112     {
113         Layer[] layer = ((RainbowPrivateKeyParameters)this.key).getLayers();
114         int numberOfLayers = layer.length;
115 
116         x = new short[((RainbowPrivateKeyParameters)this.key).getInvA2().length]; // all variables
117 
118         short[] Y_; // modified document
119         short[] y_i; // part of Y_ each polynomial
120         int counter; // index of the current part of the doc
121 
122         short[] solVec; // the solution of LES pro layer
123         short[] tmpVec;
124 
125         // the signature as an array of shorts:
126         short[] signature;
127         // the signature as a byte-array:
128         byte[] S = new byte[layer[numberOfLayers - 1].getViNext()];
129 
130         short[] msgHashVals = makeMessageRepresentative(message);
131         int itCount = 0;
132 
133         // shows if an exception is caught
134         boolean ok;
135         do
136         {
137             ok = true;
138             counter = 0;
139             try
140             {
141                 Y_ = initSign(layer, msgHashVals);
142 
143                 for (int i = 0; i < numberOfLayers; i++)
144                 {
145 
146                     y_i = new short[layer[i].getOi()];
147                     solVec = new short[layer[i].getOi()]; // solution of LES
148 
149                     /* copy oi elements of Y_ into y_i */
150                     for (int k = 0; k < layer[i].getOi(); k++)
151                     {
152                         y_i[k] = Y_[counter];
153                         counter++; // current index of Y_
154                     }
155 
156                     /*
157                      * plug in the vars of the previous layer in order to get
158                      * the vars of the current layer
159                      */
160                     solVec = cf.solveEquation(layer[i].plugInVinegars(x), y_i);
161 
162                     if (solVec == null)
163                     { // LES is not solveable
164                         throw new Exception("LES is not solveable!");
165                     }
166 
167                     /* copy the new vars into the x-array */
168                     for (int j = 0; j < solVec.length; j++)
169                     {
170                         x[layer[i].getVi() + j] = solVec[j];
171                     }
172                 }
173 
174                 /* apply the inverse of L2: (signature = A2^{-1}*(b2+x)) */
175                 tmpVec = cf.addVect(((RainbowPrivateKeyParameters)this.key).getB2(), x);
176                 signature = cf.multiplyMatrix(((RainbowPrivateKeyParameters)this.key).getInvA2(), tmpVec);
177 
178                 /* cast signature from short[] to byte[] */
179                 for (int i = 0; i < S.length; i++)
180                 {
181                     S[i] = ((byte)signature[i]);
182                 }
183             }
184             catch (Exception se)
185             {
186                 // if one of the LESs was not solveable - sign again
187                 ok = false;
188             }
189         }
190         while (!ok && ++itCount < MAXITS);
191         /* return the signature in bytes */
192 
193         if (itCount == MAXITS)
194         {
195             throw new IllegalStateException("unable to generate signature - LES not solvable");
196         }
197 
198         return S;
199     }
200 
201     /**
202      * This function verifies the signature of the message that has been
203      * updated, with the aid of the public key.
204      *
205      * @param message   the message
206      * @param signature the signature of the message
207      * @return true if the signature has been verified, false otherwise.
208      */
verifySignature(byte[] message, byte[] signature)209     public boolean verifySignature(byte[] message, byte[] signature)
210     {
211         short[] sigInt = new short[signature.length];
212         short tmp;
213 
214         for (int i = 0; i < signature.length; i++)
215         {
216             tmp = (short)signature[i];
217             tmp &= (short)0xff;
218             sigInt[i] = tmp;
219         }
220 
221         short[] msgHashVal = makeMessageRepresentative(message);
222 
223         // verify
224         short[] verificationResult = verifySignatureIntern(sigInt);
225 
226         // compare
227         boolean verified = true;
228         if (msgHashVal.length != verificationResult.length)
229         {
230             return false;
231         }
232         for (int i = 0; i < msgHashVal.length; i++)
233         {
234             verified = verified && msgHashVal[i] == verificationResult[i];
235         }
236 
237         return verified;
238     }
239 
240     /**
241      * Signature verification using public key
242      *
243      * @param signature vector of dimension n
244      * @return document hash of length n - v1
245      */
verifySignatureIntern(short[] signature)246     private short[] verifySignatureIntern(short[] signature)
247     {
248 
249         short[][] coeff_quadratic = ((RainbowPublicKeyParameters)this.key).getCoeffQuadratic();
250         short[][] coeff_singular = ((RainbowPublicKeyParameters)this.key).getCoeffSingular();
251         short[] coeff_scalar = ((RainbowPublicKeyParameters)this.key).getCoeffScalar();
252 
253         short[] rslt = new short[coeff_quadratic.length];// n - v1
254         int n = coeff_singular[0].length;
255         int offset = 0; // array position
256         short tmp = 0; // for scalar
257 
258         for (int p = 0; p < coeff_quadratic.length; p++)
259         { // no of polynomials
260             offset = 0;
261             for (int x = 0; x < n; x++)
262             {
263                 // calculate quadratic terms
264                 for (int y = x; y < n; y++)
265                 {
266                     tmp = GF2Field.multElem(coeff_quadratic[p][offset],
267                         GF2Field.multElem(signature[x], signature[y]));
268                     rslt[p] = GF2Field.addElem(rslt[p], tmp);
269                     offset++;
270                 }
271                 // calculate singular terms
272                 tmp = GF2Field.multElem(coeff_singular[p][x], signature[x]);
273                 rslt[p] = GF2Field.addElem(rslt[p], tmp);
274             }
275             // add scalar
276             rslt[p] = GF2Field.addElem(rslt[p], coeff_scalar[p]);
277         }
278 
279         return rslt;
280     }
281 
282     /**
283      * This function creates the representative of the message which gets signed
284      * or verified.
285      *
286      * @param message the message
287      * @return message representative
288      */
makeMessageRepresentative(byte[] message)289     private short[] makeMessageRepresentative(byte[] message)
290     {
291         // the message representative
292         short[] output = new short[this.signableDocumentLength];
293 
294         int h = 0;
295         int i = 0;
296         do
297         {
298             if (i >= message.length)
299             {
300                 break;
301             }
302             output[i] = (short)message[h];
303             output[i] &= (short)0xff;
304             h++;
305             i++;
306         }
307         while (i < output.length);
308 
309         return output;
310     }
311 }
312