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 Basis of three polynomials each, except the zeroth basis for which h is undefined.
/** * 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
Params:
  • b – an encoded private key
  • params – the NtruSign parameters to use
/** * 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
Params:
  • is – an input stream
  • params – the NtruSign parameters to use
/** * 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.
Params:
  • b – a NtruSign basis
/** * Adds a basis to the key. * * @param b a NtruSign basis */
private void add(Basis b) { bases.add(b); }
Returns the i-th basis
Params:
  • i – the index
Returns:the basis at index i
/** * 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
Returns:the encoded key
/** * 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
Params:
  • os – an output stream
Throws:
/** * 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 f, f', h.
/** * 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 f, f', h.
Params:
  • f –
  • fPrime –
  • h –
  • params – NtruSign parameters
/** * 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.
Params:
  • is – an input stream
  • params – NtruSign parameters
  • include_h – whether to read the polynomial h (true) or only f and f' (false)
/** * 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
Params:
  • os – an output stream
  • include_h – whether to write the polynomial h (true) or only f and f' (false)
Throws:
/** * 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; } } }