| package org.bouncycastle.pqc.crypto.ntru; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.bouncycastle.crypto.params.AsymmetricKeyParameter; |
| import org.bouncycastle.pqc.math.ntru.polynomial.DenseTernaryPolynomial; |
| import org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; |
| import org.bouncycastle.pqc.math.ntru.polynomial.Polynomial; |
| import org.bouncycastle.pqc.math.ntru.polynomial.ProductFormPolynomial; |
| import org.bouncycastle.pqc.math.ntru.polynomial.SparseTernaryPolynomial; |
| |
| /** |
| * A NtruSign private key comprises one or more {@link NTRUSigningPrivateKeyParameters.Basis} of three polynomials each, |
| * except the zeroth basis for which <code>h</code> is undefined. |
| */ |
| public class NTRUSigningPrivateKeyParameters |
| extends AsymmetricKeyParameter |
| { |
| private List<Basis> bases; |
| private NTRUSigningPublicKeyParameters publicKey; |
| |
| /** |
| * Constructs a new private key from a byte array |
| * |
| * @param b an encoded private key |
| * @param params the NtruSign parameters to use |
| */ |
| public NTRUSigningPrivateKeyParameters(byte[] b, NTRUSigningKeyGenerationParameters params) |
| throws IOException |
| { |
| this(new ByteArrayInputStream(b), params); |
| } |
| |
| /** |
| * Constructs a new private key from an input stream |
| * |
| * @param is an input stream |
| * @param params the NtruSign parameters to use |
| */ |
| public NTRUSigningPrivateKeyParameters(InputStream is, NTRUSigningKeyGenerationParameters params) |
| throws IOException |
| { |
| super(true); |
| bases = new ArrayList<Basis>(); |
| for (int i = 0; i <= params.B; i++) |
| // include a public key h[i] in all bases except for the first one |
| { |
| add(new Basis(is, params, i != 0)); |
| } |
| publicKey = new NTRUSigningPublicKeyParameters(is, params.getSigningParameters()); |
| } |
| |
| public NTRUSigningPrivateKeyParameters(List<Basis> bases, NTRUSigningPublicKeyParameters publicKey) |
| { |
| super(true); |
| this.bases = new ArrayList<Basis>(bases); |
| this.publicKey = publicKey; |
| } |
| |
| /** |
| * Adds a basis to the key. |
| * |
| * @param b a NtruSign basis |
| */ |
| private void add(Basis b) |
| { |
| bases.add(b); |
| } |
| |
| /** |
| * Returns the <code>i</code>-th basis |
| * |
| * @param i the index |
| * @return the basis at index <code>i</code> |
| */ |
| public Basis getBasis(int i) |
| { |
| return bases.get(i); |
| } |
| |
| public NTRUSigningPublicKeyParameters getPublicKey() |
| { |
| return publicKey; |
| } |
| |
| /** |
| * Converts the key to a byte array |
| * |
| * @return the encoded key |
| */ |
| public byte[] getEncoded() |
| throws IOException |
| { |
| ByteArrayOutputStream os = new ByteArrayOutputStream(); |
| for (int i = 0; i < bases.size(); i++) |
| { |
| // all bases except for the first one contain a public key |
| bases.get(i).encode(os, i != 0); |
| } |
| |
| os.write(publicKey.getEncoded()); |
| |
| return os.toByteArray(); |
| } |
| |
| /** |
| * Writes the key to an output stream |
| * |
| * @param os an output stream |
| * @throws IOException |
| */ |
| public void writeTo(OutputStream os) |
| throws IOException |
| { |
| os.write(getEncoded()); |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result; |
| if (bases==null) return result; |
| result += bases.hashCode(); |
| for (Basis basis : bases) |
| { |
| result += basis.hashCode(); |
| } |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) |
| { |
| if (this == obj) |
| { |
| return true; |
| } |
| if (obj == null) |
| { |
| return false; |
| } |
| if (getClass() != obj.getClass()) |
| { |
| return false; |
| } |
| NTRUSigningPrivateKeyParameters other = (NTRUSigningPrivateKeyParameters)obj; |
| if ((bases == null) != (other.bases == null)) |
| { |
| return false; |
| } |
| if (bases == null) |
| { |
| return true; |
| } |
| if (bases.size() != other.bases.size()) |
| { |
| return false; |
| } |
| for (int i = 0; i < bases.size(); i++) |
| { |
| Basis basis1 = bases.get(i); |
| Basis basis2 = other.bases.get(i); |
| if (!basis1.f.equals(basis2.f)) |
| { |
| return false; |
| } |
| if (!basis1.fPrime.equals(basis2.fPrime)) |
| { |
| return false; |
| } |
| if (i != 0 && !basis1.h.equals(basis2.h)) // don't compare h for the 0th basis |
| { |
| return false; |
| } |
| if (!basis1.params.equals(basis2.params)) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /** |
| * A NtruSign basis. Contains three polynomials <code>f, f', h</code>. |
| */ |
| public static class Basis |
| { |
| public Polynomial f; |
| public Polynomial fPrime; |
| public IntegerPolynomial h; |
| NTRUSigningKeyGenerationParameters params; |
| |
| /** |
| * Constructs a new basis from polynomials <code>f, f', h</code>. |
| * |
| * @param f |
| * @param fPrime |
| * @param h |
| * @param params NtruSign parameters |
| */ |
| protected Basis(Polynomial f, Polynomial fPrime, IntegerPolynomial h, NTRUSigningKeyGenerationParameters params) |
| { |
| this.f = f; |
| this.fPrime = fPrime; |
| this.h = h; |
| this.params = params; |
| } |
| |
| /** |
| * Reads a basis from an input stream and constructs a new basis. |
| * |
| * @param is an input stream |
| * @param params NtruSign parameters |
| * @param include_h whether to read the polynomial <code>h</code> (<code>true</code>) or only <code>f</code> and <code>f'</code> (<code>false</code>) |
| */ |
| Basis(InputStream is, NTRUSigningKeyGenerationParameters params, boolean include_h) |
| throws IOException |
| { |
| int N = params.N; |
| int q = params.q; |
| int d1 = params.d1; |
| int d2 = params.d2; |
| int d3 = params.d3; |
| boolean sparse = params.sparse; |
| this.params = params; |
| |
| if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) |
| { |
| f = ProductFormPolynomial.fromBinary(is, N, d1, d2, d3 + 1, d3); |
| } |
| else |
| { |
| IntegerPolynomial fInt = IntegerPolynomial.fromBinary3Tight(is, N); |
| f = sparse ? new SparseTernaryPolynomial(fInt) : new DenseTernaryPolynomial(fInt); |
| } |
| |
| if (params.basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD) |
| { |
| IntegerPolynomial fPrimeInt = IntegerPolynomial.fromBinary(is, N, q); |
| for (int i = 0; i < fPrimeInt.coeffs.length; i++) |
| { |
| fPrimeInt.coeffs[i] -= q / 2; |
| } |
| fPrime = fPrimeInt; |
| } |
| else if (params.polyType == NTRUParameters.TERNARY_POLYNOMIAL_TYPE_PRODUCT) |
| { |
| fPrime = ProductFormPolynomial.fromBinary(is, N, d1, d2, d3 + 1, d3); |
| } |
| else |
| { |
| fPrime = IntegerPolynomial.fromBinary3Tight(is, N); |
| } |
| |
| if (include_h) |
| { |
| h = IntegerPolynomial.fromBinary(is, N, q); |
| } |
| } |
| |
| /** |
| * Writes the basis to an output stream |
| * |
| * @param os an output stream |
| * @param include_h whether to write the polynomial <code>h</code> (<code>true</code>) or only <code>f</code> and <code>f'</code> (<code>false</code>) |
| * @throws IOException |
| */ |
| void encode(OutputStream os, boolean include_h) |
| throws IOException |
| { |
| int q = params.q; |
| |
| os.write(getEncoded(f)); |
| if (params.basisType == NTRUSigningKeyGenerationParameters.BASIS_TYPE_STANDARD) |
| { |
| IntegerPolynomial fPrimeInt = fPrime.toIntegerPolynomial(); |
| for (int i = 0; i < fPrimeInt.coeffs.length; i++) |
| { |
| fPrimeInt.coeffs[i] += q / 2; |
| } |
| os.write(fPrimeInt.toBinary(q)); |
| } |
| else |
| { |
| os.write(getEncoded(fPrime)); |
| } |
| if (include_h) |
| { |
| os.write(h.toBinary(q)); |
| } |
| } |
| |
| private byte[] getEncoded(Polynomial p) |
| { |
| if (p instanceof ProductFormPolynomial) |
| { |
| return ((ProductFormPolynomial)p).toBinary(); |
| } |
| else |
| { |
| return p.toIntegerPolynomial().toBinary3Tight(); |
| } |
| } |
| |
| @Override |
| public int hashCode() |
| { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((f == null) ? 0 : f.hashCode()); |
| result = prime * result + ((fPrime == null) ? 0 : fPrime.hashCode()); |
| result = prime * result + ((h == null) ? 0 : h.hashCode()); |
| result = prime * result + ((params == null) ? 0 : params.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) |
| { |
| if (this == obj) |
| { |
| return true; |
| } |
| if (obj == null) |
| { |
| return false; |
| } |
| if (!(obj instanceof Basis)) |
| { |
| return false; |
| } |
| Basis other = (Basis)obj; |
| if (f == null) |
| { |
| if (other.f != null) |
| { |
| return false; |
| } |
| } |
| else if (!f.equals(other.f)) |
| { |
| return false; |
| } |
| if (fPrime == null) |
| { |
| if (other.fPrime != null) |
| { |
| return false; |
| } |
| } |
| else if (!fPrime.equals(other.fPrime)) |
| { |
| return false; |
| } |
| if (h == null) |
| { |
| if (other.h != null) |
| { |
| return false; |
| } |
| } |
| else if (!h.equals(other.h)) |
| { |
| return false; |
| } |
| if (params == null) |
| { |
| if (other.params != null) |
| { |
| return false; |
| } |
| } |
| else if (!params.equals(other.params)) |
| { |
| return false; |
| } |
| return true; |
| } |
| } |
| } |