//*********************************************************
//
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the Apache License Version 2.0.
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************
package com.microsoft.uprove;
import java.io.IOException;
import java.math.BigInteger;
/**
* Represents an immutable group of prime order.
* <p>
* In addition to implementing all abstract methods in this class, extenders
* must provide an implementation of
* {@link Hashable#addToDigest(com.microsoft.uprove.HashUpdater) addToDigest}
* that adds the parameters that define the group to a hash. For example, the
* subgroup implementation updates the digest with the
* big-endian ordered two's complement encodings of its <code>P</code>,
* <code>Q</code>, and <code>G</code> values.
* </p>
* <p>
* The elements within the group are represented by an implementation of the
* {@link GroupElement} interface.
* </p>
* <p>
* Additionally, all groups possess an instance of the {@link FieldZq} class,
* representing the field defined by the group's order.
* </p>
*/
public abstract class PrimeOrderGroup implements Hashable {
private final FieldZq Zq;
/**
* Constructor for use by implementors.
* @param q the group's prime order.
* @throws NullPointerException if <code>q</code> is <code>null</code>.
* @throws IllegalArgumentException if <code>q</code> is not a positive
* prime number.
*/
protected PrimeOrderGroup(final BigInteger q) {
// we may be called by user code (our implementors), so make a
// defensive copy of q
this.Zq = FieldZq.getInstance(new BigInteger(q.toByteArray()));
}
/**
* Returns the order of the group.
* @return the order of the group.
*/
public final BigInteger getOrder() {
return Zq.getQ();
}
/**
* Returns the generator of the group.
* <p>
* Implementations MUST return an instance of a construction-specific
* element class that is a generator within the group. Additionally, the
* instance returned MUST be distinct from any other element instances
* since the <code>GroupElement</code> interface defines a mutable and
* erasable object.
* </p>
* @return the generator of the group. Ownership of the referent is given
* to the caller.
*/
public abstract GroupElement getGenerator();
/**
* Returns the identity element of the group.
* <p>
* Implementations MUST return an instance of a construction-specific
* element class that holds the group's identity element. Additionally, the
* instance returned MUST be distinct from any other element instances
* since the <code>GroupElement</code> interface defines a mutable and
* erasable object.
* </p>
* @return the identity element of the group. Ownership of the referent is
* given to the caller.
*/
public abstract GroupElement getIdentity();
/**
* Returns the field <code>Z<sub>q</sub></code> defined by the group's
* order.
* @return the group's <code>Z<sub>q</sub></code> field.
*/
public final FieldZq getZq() {
return Zq;
}
/**
* Returns a <code>GroupElement</code> with the value encoded in the
* given byte array.
* <p>
* Implementations MUST return an instance of a construction-specific
* element class that holds the value encoded in <code>data</code>. If
* the format of the bytes in <code>data</code> is invalid or if the
* value decoded from <code>data</code> does not represent an element in
* <code>this</code> group, the implementation MUST throw a
* <code>IOException</code>.
* </p>
* @param data group element data. The caller's ownership of the referent
* is preserved.
* @return an element in the group. Ownership of the referent is given to
* the caller.
* @throws IOException if <code>data</code> is
* malformed, or does not represent an element within <code>this</code>
* group.
* @see GroupElement#toByteArray()
*/
public abstract GroupElement getElement(byte[] data)
throws IOException;
/**
* Returns an array of <code>GroupElement</code> instances with the values
* indicated in the provided array of encoded group elements.
* @param specs an array of encoded group elements. The caller's ownership
* of the referent is preserved.
* @return an array of <code>GroupElement</code> instances. Ownership of
* the referent is given to the caller.
* @throws IOException if any element in
* <code>specs</code> is malformed or does not represent an element within
* <code>this</code> group.
* @see GroupElement#toByteArray()
* @see #getElement(byte[])
*/
public final GroupElement[] getElementArray(final byte[][] specs)
throws IOException {
final int len = specs.length;
final GroupElement[] retVal = new GroupElement[len];
for (int i = 0; i < len; ++i) {
retVal[i] = getElement(specs[i]);
}
return retVal;
}
/**
* Returns an array of encoded group elements corresponding to the
* elements in the provided array.
* @param elements an array of <code>GroupElement</code> instances.
* The caller's ownership of the referent is preserved.
* @return an array of encoded group elements. Ownership of the referent is
* given to the caller.
* @throws IllegalArgumentException if the list contains elements that
* belong to a group other than <code>this</code>.
* @see GroupElement#toByteArray()
*/
public final byte[][] getEncodedElements(final GroupElement[] elements) {
// create the resulting array
byte[][] retVal = new byte[elements.length][];
// populate it, checking each item as we go
for (int i = 0; i < elements.length; i++) {
final GroupElement elem = elements[i];
if (elem.getGroup() != this) {
throw new IllegalArgumentException();
}
retVal[i] = elem.toByteArray();
}
return retVal;
}
/**
* Returns the size (in bytes) of the largest encoded element.
* @return the size (in bytes) of the largest encoded element.
*/
public abstract int getMaxEncodedElementSize();
/**
* Indicates whether some other object is "equal to" this group.
* <p>
* This method returns <code>true</code> if <code>obj</code> is a
* <code>PrimeOrderGroup</code> of the same prime order as
* <code>this</code> group. Subclasses MUST override this method with
* their own implementation that ensures that <code>obj</code> is of the
* same type as <code>this</code> and that it was constructed with the same
* parameters as <code>this</code>.
* @param obj the reference object with which to compare.
* @return <code>true</code> if this group is the same as the obj argument;
* <code>false</code> otherwise.
*/
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof PrimeOrderGroup)) {
return false;
}
PrimeOrderGroup pog = (PrimeOrderGroup) obj;
return Zq.equals(pog.Zq);
}
/**
* Returns a hash code value for the group.
* <p>
* This method computes a hash based on the value of the group's prime
* order. Subclasses MUST override this method with their own
* implementation that ensures that it obeys the contract between
* {@link Object#hashCode()} and {@link Object#equals(java.lang.Object)}.
* </p>
* @return {@inheritDoc}
*/
public int hashCode() {
return 421 * 163 + Zq.hashCode();
}
/**
* Validates that the group is well-formed, i.e. that the order
* <code>q</code> is prime, that the generator is a member of the group,
* and any other checks required by a particular group construction.
* @throws IllegalStateException if the group is malformed.
*/
public final void validate() {
// the constructor ensures that q is in range
// validate the exponent field (i.e. q is prime)
Zq.validate();
// delegate group-specific validation to the implementation
doGroupSpecificValidate();
}
/**
* Invoked during group validation to allow implementations to provide
* group-specific validation.
* @throws IllegalStateException if the group is malformed.
*/
protected abstract void doGroupSpecificValidate();
}