1 package org.bouncycastle.pqc.jcajce.provider.xmss;
2 
3 import java.io.IOException;
4 import java.io.ObjectInputStream;
5 import java.io.ObjectOutputStream;
6 import java.security.PublicKey;
7 
8 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
9 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
10 import org.bouncycastle.crypto.CipherParameters;
11 import org.bouncycastle.pqc.crypto.util.PublicKeyFactory;
12 import org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory;
13 import org.bouncycastle.pqc.crypto.xmss.XMSSPublicKeyParameters;
14 import org.bouncycastle.pqc.jcajce.interfaces.XMSSKey;
15 import org.bouncycastle.util.Arrays;
16 
17 public class BCXMSSPublicKey
18     implements PublicKey, XMSSKey
19 {
20     private static final long serialVersionUID = -5617456225328969766L;
21 
22     private transient XMSSPublicKeyParameters keyParams;
23     private transient ASN1ObjectIdentifier treeDigest;
24 
BCXMSSPublicKey( ASN1ObjectIdentifier treeDigest, XMSSPublicKeyParameters keyParams)25     public BCXMSSPublicKey(
26         ASN1ObjectIdentifier treeDigest,
27         XMSSPublicKeyParameters keyParams)
28     {
29         this.treeDigest = treeDigest;
30         this.keyParams = keyParams;
31     }
32 
BCXMSSPublicKey(SubjectPublicKeyInfo keyInfo)33     public BCXMSSPublicKey(SubjectPublicKeyInfo keyInfo)
34         throws IOException
35     {
36         init(keyInfo);
37     }
38 
init(SubjectPublicKeyInfo keyInfo)39     private void init(SubjectPublicKeyInfo keyInfo)
40         throws IOException
41     {
42         this.keyParams = (XMSSPublicKeyParameters)PublicKeyFactory.createKey(keyInfo);
43         this.treeDigest = DigestUtil.getDigestOID(keyParams.getTreeDigest());
44     }
45 
46     /**
47      * @return name of the algorithm - "XMSS"
48      */
getAlgorithm()49     public final String getAlgorithm()
50     {
51         return "XMSS";
52     }
53 
getEncoded()54     public byte[] getEncoded()
55     {
56         try
57         {
58             SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyParams);
59             return pki.getEncoded();
60         }
61         catch (IOException e)
62         {
63             return null;
64         }
65     }
66 
getFormat()67     public String getFormat()
68     {
69         return "X.509";
70     }
71 
getKeyParams()72     CipherParameters getKeyParams()
73     {
74         return keyParams;
75     }
76 
equals(Object o)77     public boolean equals(Object o)
78     {
79         if (o == this)
80         {
81             return true;
82         }
83 
84         if (o instanceof BCXMSSPublicKey)
85         {
86             BCXMSSPublicKey otherKey = (BCXMSSPublicKey)o;
87 
88             try
89             {
90                 return treeDigest.equals(otherKey.treeDigest) && Arrays.areEqual(keyParams.getEncoded(), otherKey.keyParams.getEncoded());
91             }
92             catch (IOException e)
93             {
94                 return false;
95             }
96         }
97 
98         return false;
99     }
100 
hashCode()101     public int hashCode()
102     {
103         try
104         {
105             return treeDigest.hashCode() + 37 * Arrays.hashCode(keyParams.getEncoded());
106         }
107         catch (IOException e)
108         {
109             // should never happen, but...
110             return treeDigest.hashCode();
111         }
112     }
113 
getHeight()114     public int getHeight()
115     {
116         return keyParams.getParameters().getHeight();
117     }
118 
getTreeDigest()119     public String getTreeDigest()
120     {
121         return DigestUtil.getXMSSDigestName(treeDigest);
122     }
123 
readObject( ObjectInputStream in)124     private void readObject(
125         ObjectInputStream in)
126         throws IOException, ClassNotFoundException
127     {
128         in.defaultReadObject();
129 
130         byte[] enc = (byte[])in.readObject();
131 
132         init(SubjectPublicKeyInfo.getInstance(enc));
133     }
134 
writeObject( ObjectOutputStream out)135     private void writeObject(
136         ObjectOutputStream out)
137         throws IOException
138     {
139         out.defaultWriteObject();
140 
141         out.writeObject(this.getEncoded());
142     }
143 }
144