blob: 7c21691d9005dc3508628f7e978541d3f5631768 [file] [log] [blame]
package org.bouncycastle.pqc.asn1;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.pqc.crypto.rainbow.Layer;
import org.bouncycastle.pqc.crypto.rainbow.util.RainbowUtil;
/**
* Return the key data to encode in the PrivateKeyInfo structure.
* <p>
* The ASN.1 definition of the key structure is
* <pre>
* RainbowPrivateKey ::= SEQUENCE {
* CHOICE
* {
* oid OBJECT IDENTIFIER -- OID identifying the algorithm
* version INTEGER -- 0
* }
* A1inv SEQUENCE OF OCTET STRING -- inversed matrix of L1
* b1 OCTET STRING -- translation vector of L1
* A2inv SEQUENCE OF OCTET STRING -- inversed matrix of L2
* b2 OCTET STRING -- translation vector of L2
* vi OCTET STRING -- num of elmts in each Set S
* layers SEQUENCE OF Layer -- layers of F
* }
*
* Layer ::= SEQUENCE OF Poly
*
* Poly ::= SEQUENCE {
* alpha SEQUENCE OF OCTET STRING
* beta SEQUENCE OF OCTET STRING
* gamma OCTET STRING
* eta INTEGER
* }
* </pre>
*/
public class RainbowPrivateKey
extends ASN1Object
{
private ASN1Integer version;
private ASN1ObjectIdentifier oid;
private byte[][] invA1;
private byte[] b1;
private byte[][] invA2;
private byte[] b2;
private byte[] vi;
private Layer[] layers;
private RainbowPrivateKey(ASN1Sequence seq)
{
// <oidString> or version
if (seq.getObjectAt(0) instanceof ASN1Integer)
{
version = ASN1Integer.getInstance(seq.getObjectAt(0));
}
else
{
oid = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
}
// <A1inv>
ASN1Sequence asnA1 = (ASN1Sequence)seq.getObjectAt(1);
invA1 = new byte[asnA1.size()][];
for (int i = 0; i < asnA1.size(); i++)
{
invA1[i] = ((ASN1OctetString)asnA1.getObjectAt(i)).getOctets();
}
// <b1>
ASN1Sequence asnb1 = (ASN1Sequence)seq.getObjectAt(2);
b1 = ((ASN1OctetString)asnb1.getObjectAt(0)).getOctets();
// <A2inv>
ASN1Sequence asnA2 = (ASN1Sequence)seq.getObjectAt(3);
invA2 = new byte[asnA2.size()][];
for (int j = 0; j < asnA2.size(); j++)
{
invA2[j] = ((ASN1OctetString)asnA2.getObjectAt(j)).getOctets();
}
// <b2>
ASN1Sequence asnb2 = (ASN1Sequence)seq.getObjectAt(4);
b2 = ((ASN1OctetString)asnb2.getObjectAt(0)).getOctets();
// <vi>
ASN1Sequence asnvi = (ASN1Sequence)seq.getObjectAt(5);
vi = ((ASN1OctetString)asnvi.getObjectAt(0)).getOctets();
// <layers>
ASN1Sequence asnLayers = (ASN1Sequence)seq.getObjectAt(6);
byte[][][][] alphas = new byte[asnLayers.size()][][][];
byte[][][][] betas = new byte[asnLayers.size()][][][];
byte[][][] gammas = new byte[asnLayers.size()][][];
byte[][] etas = new byte[asnLayers.size()][];
// a layer:
for (int l = 0; l < asnLayers.size(); l++)
{
ASN1Sequence asnLayer = (ASN1Sequence)asnLayers.getObjectAt(l);
// alphas (num of alpha-2d-array = oi)
ASN1Sequence alphas3d = (ASN1Sequence)asnLayer.getObjectAt(0);
alphas[l] = new byte[alphas3d.size()][][];
for (int m = 0; m < alphas3d.size(); m++)
{
ASN1Sequence alphas2d = (ASN1Sequence)alphas3d.getObjectAt(m);
alphas[l][m] = new byte[alphas2d.size()][];
for (int n = 0; n < alphas2d.size(); n++)
{
alphas[l][m][n] = ((ASN1OctetString)alphas2d.getObjectAt(n)).getOctets();
}
}
// betas ....
ASN1Sequence betas3d = (ASN1Sequence)asnLayer.getObjectAt(1);
betas[l] = new byte[betas3d.size()][][];
for (int mb = 0; mb < betas3d.size(); mb++)
{
ASN1Sequence betas2d = (ASN1Sequence)betas3d.getObjectAt(mb);
betas[l][mb] = new byte[betas2d.size()][];
for (int nb = 0; nb < betas2d.size(); nb++)
{
betas[l][mb][nb] = ((ASN1OctetString)betas2d.getObjectAt(nb)).getOctets();
}
}
// gammas ...
ASN1Sequence gammas2d = (ASN1Sequence)asnLayer.getObjectAt(2);
gammas[l] = new byte[gammas2d.size()][];
for (int mg = 0; mg < gammas2d.size(); mg++)
{
gammas[l][mg] = ((ASN1OctetString)gammas2d.getObjectAt(mg)).getOctets();
}
// eta ...
etas[l] = ((ASN1OctetString)asnLayer.getObjectAt(3)).getOctets();
}
int numOfLayers = vi.length - 1;
this.layers = new Layer[numOfLayers];
for (int i = 0; i < numOfLayers; i++)
{
Layer l = new Layer(vi[i], vi[i + 1], RainbowUtil.convertArray(alphas[i]),
RainbowUtil.convertArray(betas[i]), RainbowUtil.convertArray(gammas[i]), RainbowUtil.convertArray(etas[i]));
this.layers[i] = l;
}
}
public RainbowPrivateKey(short[][] invA1, short[] b1, short[][] invA2,
short[] b2, int[] vi, Layer[] layers)
{
this.version = new ASN1Integer(1);
this.invA1 = RainbowUtil.convertArray(invA1);
this.b1 = RainbowUtil.convertArray(b1);
this.invA2 = RainbowUtil.convertArray(invA2);
this.b2 = RainbowUtil.convertArray(b2);
this.vi = RainbowUtil.convertIntArray(vi);
this.layers = layers;
}
public static RainbowPrivateKey getInstance(Object o)
{
if (o instanceof RainbowPrivateKey)
{
return (RainbowPrivateKey)o;
}
else if (o != null)
{
return new RainbowPrivateKey(ASN1Sequence.getInstance(o));
}
return null;
}
public ASN1Integer getVersion()
{
return version;
}
/**
* Getter for the inverse matrix of A1.
*
* @return the A1inv inverse
*/
public short[][] getInvA1()
{
return RainbowUtil.convertArray(invA1);
}
/**
* Getter for the translation part of the private quadratic map L1.
*
* @return b1 the translation part of L1
*/
public short[] getB1()
{
return RainbowUtil.convertArray(b1);
}
/**
* Getter for the translation part of the private quadratic map L2.
*
* @return b2 the translation part of L2
*/
public short[] getB2()
{
return RainbowUtil.convertArray(b2);
}
/**
* Getter for the inverse matrix of A2
*
* @return the A2inv
*/
public short[][] getInvA2()
{
return RainbowUtil.convertArray(invA2);
}
/**
* Returns the layers contained in the private key
*
* @return layers
*/
public Layer[] getLayers()
{
return this.layers;
}
/**
* Returns the array of vi-s
*
* @return the vi
*/
public int[] getVi()
{
return RainbowUtil.convertArraytoInt(vi);
}
public ASN1Primitive toASN1Primitive()
{
ASN1EncodableVector v = new ASN1EncodableVector();
// encode <oidString> or version
if (version != null)
{
v.add(version);
}
else
{
v.add(oid);
}
// encode <A1inv>
ASN1EncodableVector asnA1 = new ASN1EncodableVector();
for (int i = 0; i < invA1.length; i++)
{
asnA1.add(new DEROctetString(invA1[i]));
}
v.add(new DERSequence(asnA1));
// encode <b1>
ASN1EncodableVector asnb1 = new ASN1EncodableVector();
asnb1.add(new DEROctetString(b1));
v.add(new DERSequence(asnb1));
// encode <A2inv>
ASN1EncodableVector asnA2 = new ASN1EncodableVector();
for (int i = 0; i < invA2.length; i++)
{
asnA2.add(new DEROctetString(invA2[i]));
}
v.add(new DERSequence(asnA2));
// encode <b2>
ASN1EncodableVector asnb2 = new ASN1EncodableVector();
asnb2.add(new DEROctetString(b2));
v.add(new DERSequence(asnb2));
// encode <vi>
ASN1EncodableVector asnvi = new ASN1EncodableVector();
asnvi.add(new DEROctetString(vi));
v.add(new DERSequence(asnvi));
// encode <layers>
ASN1EncodableVector asnLayers = new ASN1EncodableVector();
// a layer:
for (int l = 0; l < layers.length; l++)
{
ASN1EncodableVector aLayer = new ASN1EncodableVector();
// alphas (num of alpha-2d-array = oi)
byte[][][] alphas = RainbowUtil.convertArray(layers[l].getCoeffAlpha());
ASN1EncodableVector alphas3d = new ASN1EncodableVector();
for (int i = 0; i < alphas.length; i++)
{
ASN1EncodableVector alphas2d = new ASN1EncodableVector();
for (int j = 0; j < alphas[i].length; j++)
{
alphas2d.add(new DEROctetString(alphas[i][j]));
}
alphas3d.add(new DERSequence(alphas2d));
}
aLayer.add(new DERSequence(alphas3d));
// betas ....
byte[][][] betas = RainbowUtil.convertArray(layers[l].getCoeffBeta());
ASN1EncodableVector betas3d = new ASN1EncodableVector();
for (int i = 0; i < betas.length; i++)
{
ASN1EncodableVector betas2d = new ASN1EncodableVector();
for (int j = 0; j < betas[i].length; j++)
{
betas2d.add(new DEROctetString(betas[i][j]));
}
betas3d.add(new DERSequence(betas2d));
}
aLayer.add(new DERSequence(betas3d));
// gammas ...
byte[][] gammas = RainbowUtil.convertArray(layers[l].getCoeffGamma());
ASN1EncodableVector asnG = new ASN1EncodableVector();
for (int i = 0; i < gammas.length; i++)
{
asnG.add(new DEROctetString(gammas[i]));
}
aLayer.add(new DERSequence(asnG));
// eta
aLayer.add(new DEROctetString(RainbowUtil.convertArray(layers[l].getCoeffEta())));
// now, layer built up. add it!
asnLayers.add(new DERSequence(aLayer));
}
v.add(new DERSequence(asnLayers));
return new DERSequence(v);
}
}