diff options
Diffstat (limited to 'core/src/main/java/org')
120 files changed, 9550 insertions, 2613 deletions
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java index 1360e8b5..1d4f5af0 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Boolean.java @@ -1,15 +1,187 @@ package org.bouncycastle.asn1; +import java.io.IOException; + +import org.bouncycastle.util.Arrays; + public class ASN1Boolean - extends DERBoolean + extends ASN1Primitive { - public ASN1Boolean(boolean value) + private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff }; + private static final byte[] FALSE_VALUE = new byte[] { 0 }; + + private byte[] value; + + public static final ASN1Boolean FALSE = new ASN1Boolean(false); + public static final ASN1Boolean TRUE = new ASN1Boolean(true); + + + /** + * return a boolean from the passed in object. + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Boolean getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Boolean) + { + return (ASN1Boolean)obj; + } + + if (obj instanceof byte[]) + { + byte[] enc = (byte[])obj; + try + { + return (ASN1Boolean)fromByteArray(enc); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct boolean from byte[]: " + e.getMessage()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an ASN1Boolean from the passed in boolean. + */ + public static ASN1Boolean getInstance( + boolean value) + { + return (value ? TRUE : FALSE); + } + + /** + * return an ASN1Boolean from the passed in value. + */ + public static ASN1Boolean getInstance( + int value) + { + return (value != 0 ? TRUE : FALSE); + } + + /** + * return a Boolean from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1Boolean getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1Boolean) + { + return getInstance(o); + } + else + { + return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets()); + } + } + + ASN1Boolean( + byte[] value) + { + if (value.length != 1) + { + throw new IllegalArgumentException("byte value should have 1 byte in it"); + } + + if (value[0] == 0) + { + this.value = FALSE_VALUE; + } + else if ((value[0] & 0xff) == 0xff) + { + this.value = TRUE_VALUE; + } + else + { + this.value = Arrays.clone(value); + } + } + + /** + * @deprecated use getInstance(boolean) method. + * @param value true or false. + */ + public ASN1Boolean( + boolean value) { - super(value); + this.value = (value) ? TRUE_VALUE : FALSE_VALUE; } - ASN1Boolean(byte[] value) + public boolean isTrue() { - super(value); + return (value[0] != 0); + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + { + return 3; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.BOOLEAN, value); + } + + protected boolean asn1Equals( + ASN1Primitive o) + { + if (o instanceof ASN1Boolean) + { + return (value[0] == ((ASN1Boolean)o).value[0]); + } + + return false; + } + + public int hashCode() + { + return value[0]; + } + + + public String toString() + { + return (value[0] != 0) ? "TRUE" : "FALSE"; + } + + static ASN1Boolean fromOctetString(byte[] value) + { + if (value.length != 1) + { + throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it"); + } + + if (value[0] == 0) + { + return FALSE; + } + else if ((value[0] & 0xff) == 0xff) + { + return TRUE; + } + else + { + return new ASN1Boolean(value); + } } } diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java index d93fd912..09a518f6 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Enumerated.java @@ -1,22 +1,162 @@ package org.bouncycastle.asn1; +import java.io.IOException; import java.math.BigInteger; +import org.bouncycastle.util.Arrays; + public class ASN1Enumerated - extends DEREnumerated + extends ASN1Primitive { - ASN1Enumerated(byte[] bytes) + byte[] bytes; + + /** + * return an integer from the passed in object + * + * @exception IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Enumerated getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1Enumerated) + { + return (ASN1Enumerated)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (ASN1Enumerated)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Enumerated from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @exception IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1Enumerated getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1Enumerated) + { + return getInstance(o); + } + else + { + return fromOctetString(((ASN1OctetString)o).getOctets()); + } + } + + /** + * @deprecated use ASN1Enumerated + */ + public ASN1Enumerated( + int value) + { + bytes = BigInteger.valueOf(value).toByteArray(); + } + + /** + * @deprecated use ASN1Enumerated + */ + public ASN1Enumerated( + BigInteger value) + { + bytes = value.toByteArray(); + } + + /** + * @deprecated use ASN1Enumerated + */ + public ASN1Enumerated( + byte[] bytes) + { + this.bytes = bytes; + } + + public BigInteger getValue() { - super(bytes); + return new BigInteger(bytes); } - public ASN1Enumerated(BigInteger value) + boolean isConstructed() { - super(value); + return false; } - public ASN1Enumerated(int value) + int encodedLength() { - super(value); + return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.ENUMERATED, bytes); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1Enumerated)) + { + return false; + } + + ASN1Enumerated other = (ASN1Enumerated)o; + + return Arrays.areEqual(this.bytes, other.bytes); + } + + public int hashCode() + { + return Arrays.hashCode(bytes); + } + + private static ASN1Enumerated[] cache = new ASN1Enumerated[12]; + + static ASN1Enumerated fromOctetString(byte[] enc) + { + if (enc.length > 1) + { + return new ASN1Enumerated(Arrays.clone(enc)); + } + + if (enc.length == 0) + { + throw new IllegalArgumentException("ENUMERATED has zero length"); + } + int value = enc[0] & 0xff; + + if (value >= cache.length) + { + return new ASN1Enumerated(Arrays.clone(enc)); + } + + ASN1Enumerated possibleMatch = cache[value]; + + if (possibleMatch == null) + { + possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc)); + } + + return possibleMatch; } } diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java b/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java index 18e89c6d..b951e745 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1Integer.java @@ -1,34 +1,150 @@ package org.bouncycastle.asn1; +import java.io.IOException; import java.math.BigInteger; import org.bouncycastle.util.Arrays; public class ASN1Integer - extends DERInteger + extends ASN1Primitive { - ASN1Integer(byte[] bytes, boolean clone) + byte[] bytes; + + /** + * return an integer from the passed in object + * + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static ASN1Integer getInstance( + Object obj) { - super(clone ? Arrays.clone(bytes) : bytes); + if (obj == null || obj instanceof ASN1Integer) + { + return (ASN1Integer)obj; + } + + if (obj instanceof byte[]) + { + try + { + return (ASN1Integer)fromByteArray((byte[])obj); + } + catch (Exception e) + { + throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); } /** - * Constructor from a byte array containing a signed representation of the number. + * return an Integer from a tagged object. * - * @param bytes a byte array containing the signed number.A copy is made of the byte array. + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @throws IllegalArgumentException if the tagged object cannot + * be converted. */ - public ASN1Integer(byte[] bytes) + public static ASN1Integer getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1Integer) + { + return getInstance(o); + } + else + { + return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } + } + + public ASN1Integer( + long value) + { + bytes = BigInteger.valueOf(value).toByteArray(); + } + + public ASN1Integer( + BigInteger value) + { + bytes = value.toByteArray(); + } + + public ASN1Integer( + byte[] bytes) { this(bytes, true); } - public ASN1Integer(BigInteger value) + ASN1Integer(byte[] bytes, boolean clone) + { + this.bytes = (clone) ? Arrays.clone(bytes) : bytes; + } + + public BigInteger getValue() + { + return new BigInteger(bytes); + } + + /** + * in some cases positive values get crammed into a space, + * that's not quite big enough... + */ + public BigInteger getPositiveValue() + { + return new BigInteger(1, bytes); + } + + boolean isConstructed() { - super(value); + return false; } - public ASN1Integer(long value) + int encodedLength() { - super(value); + return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; } + + void encode( + ASN1OutputStream out) + throws IOException + { + out.writeEncoded(BERTags.INTEGER, bytes); + } + + public int hashCode() + { + int value = 0; + + for (int i = 0; i != bytes.length; i++) + { + value ^= (bytes[i] & 0xff) << (i % 4); + } + + return value; + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1Integer)) + { + return false; + } + + ASN1Integer other = (ASN1Integer)o; + + return Arrays.areEqual(bytes, other.bytes); + } + + public String toString() + { + return getValue().toString(); + } + } diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java index 98f46a6d..6bd335bc 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java +++ b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java @@ -1,21 +1,429 @@ package org.bouncycastle.asn1; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; + +import org.bouncycastle.util.Arrays; + public class ASN1ObjectIdentifier - extends DERObjectIdentifier + extends ASN1Primitive { - public ASN1ObjectIdentifier(String identifier) + String identifier; + + private byte[] body; + + /** + * return an OID from the passed in object + * + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static ASN1ObjectIdentifier getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)obj; + } + + if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); + } + + if (obj instanceof byte[]) + { + byte[] enc = (byte[])obj; + try + { + return (ASN1ObjectIdentifier)fromByteArray(enc); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct object identifier from byte[]: " + e.getMessage()); + } + } + + throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); + } + + /** + * return an Object Identifier from a tagged object. + * + * @param obj the tagged object holding the object we want + * @param explicit true if the object is meant to be explicitly + * tagged false otherwise. + * @throws IllegalArgumentException if the tagged object cannot + * be converted. + */ + public static ASN1ObjectIdentifier getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + ASN1Primitive o = obj.getObject(); + + if (explicit || o instanceof ASN1ObjectIdentifier) + { + return getInstance(o); + } + else + { + return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets()); + } + } + + private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f; + + ASN1ObjectIdentifier( + byte[] bytes) + { + StringBuffer objId = new StringBuffer(); + long value = 0; + BigInteger bigValue = null; + boolean first = true; + + for (int i = 0; i != bytes.length; i++) + { + int b = bytes[i] & 0xff; + + if (value <= LONG_LIMIT) + { + value += (b & 0x7f); + if ((b & 0x80) == 0) // end of number reached + { + if (first) + { + if (value < 40) + { + objId.append('0'); + } + else if (value < 80) + { + objId.append('1'); + value -= 40; + } + else + { + objId.append('2'); + value -= 80; + } + first = false; + } + + objId.append('.'); + objId.append(value); + value = 0; + } + else + { + value <<= 7; + } + } + else + { + if (bigValue == null) + { + bigValue = BigInteger.valueOf(value); + } + bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); + if ((b & 0x80) == 0) + { + if (first) + { + objId.append('2'); + bigValue = bigValue.subtract(BigInteger.valueOf(80)); + first = false; + } + + objId.append('.'); + objId.append(bigValue); + bigValue = null; + value = 0; + } + else + { + bigValue = bigValue.shiftLeft(7); + } + } + } + + this.identifier = objId.toString(); + this.body = Arrays.clone(bytes); + } + + public ASN1ObjectIdentifier( + String identifier) { - super(identifier); + if (identifier == null) + { + throw new IllegalArgumentException("'identifier' cannot be null"); + } + if (!isValidIdentifier(identifier)) + { + throw new IllegalArgumentException("string " + identifier + " not an OID"); + } + + this.identifier = identifier; } - ASN1ObjectIdentifier(byte[] bytes) + ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branchID) { - super(bytes); + if (!isValidBranchID(branchID, 0)) + { + throw new IllegalArgumentException("string " + branchID + " not a valid OID branch"); + } + + this.identifier = oid.getId() + "." + branchID; } - ASN1ObjectIdentifier(ASN1ObjectIdentifier oid, String branch) + public String getId() { - super(oid, branch); + return identifier; + } + + private void writeField( + ByteArrayOutputStream out, + long fieldValue) + { + byte[] result = new byte[9]; + int pos = 8; + result[pos] = (byte)((int)fieldValue & 0x7f); + while (fieldValue >= (1L << 7)) + { + fieldValue >>= 7; + result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80); + } + out.write(result, pos, 9 - pos); + } + + private void writeField( + ByteArrayOutputStream out, + BigInteger fieldValue) + { + int byteCount = (fieldValue.bitLength() + 6) / 7; + if (byteCount == 0) + { + out.write(0); + } + else + { + BigInteger tmpValue = fieldValue; + byte[] tmp = new byte[byteCount]; + for (int i = byteCount - 1; i >= 0; i--) + { + tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80); + tmpValue = tmpValue.shiftRight(7); + } + tmp[byteCount - 1] &= 0x7f; + out.write(tmp, 0, tmp.length); + } + } + + private void doOutput(ByteArrayOutputStream aOut) + { + OIDTokenizer tok = new OIDTokenizer(identifier); + int first = Integer.parseInt(tok.nextToken()) * 40; + + String secondToken = tok.nextToken(); + if (secondToken.length() <= 18) + { + writeField(aOut, first + Long.parseLong(secondToken)); + } + else + { + writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first))); + } + + while (tok.hasMoreTokens()) + { + String token = tok.nextToken(); + if (token.length() <= 18) + { + writeField(aOut, Long.parseLong(token)); + } + else + { + writeField(aOut, new BigInteger(token)); + } + } + } + + protected synchronized byte[] getBody() + { + if (body == null) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + doOutput(bOut); + + body = bOut.toByteArray(); + } + + return body; + } + + boolean isConstructed() + { + return false; + } + + int encodedLength() + throws IOException + { + int length = getBody().length; + + return 1 + StreamUtil.calculateBodyLength(length) + length; + } + + void encode( + ASN1OutputStream out) + throws IOException + { + byte[] enc = getBody(); + + out.write(BERTags.OBJECT_IDENTIFIER); + out.writeLength(enc.length); + out.write(enc); + } + + public int hashCode() + { + return identifier.hashCode(); + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1ObjectIdentifier)) + { + return false; + } + + return identifier.equals(((ASN1ObjectIdentifier)o).identifier); + } + + public String toString() + { + return getId(); + } + + private static boolean isValidBranchID( + String branchID, int start) + { + boolean periodAllowed = false; + + int pos = branchID.length(); + while (--pos >= start) + { + char ch = branchID.charAt(pos); + + // TODO Leading zeroes? + if ('0' <= ch && ch <= '9') + { + periodAllowed = true; + continue; + } + + if (ch == '.') + { + if (!periodAllowed) + { + return false; + } + + periodAllowed = false; + continue; + } + + return false; + } + + return periodAllowed; + } + + private static boolean isValidIdentifier( + String identifier) + { + if (identifier.length() < 3 || identifier.charAt(1) != '.') + { + return false; + } + + char first = identifier.charAt(0); + if (first < '0' || first > '2') + { + return false; + } + + return isValidBranchID(identifier, 2); + } + + private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][]; + + static ASN1ObjectIdentifier fromOctetString(byte[] enc) + { + if (enc.length < 3) + { + return new ASN1ObjectIdentifier(enc); + } + + int idx1 = enc[enc.length - 2] & 0xff; + // in this case top bit is always zero + int idx2 = enc[enc.length - 1] & 0x7f; + + ASN1ObjectIdentifier possibleMatch; + + synchronized (cache) + { + ASN1ObjectIdentifier[] first = cache[idx1]; + if (first == null) + { + first = cache[idx1] = new ASN1ObjectIdentifier[128]; + } + + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + idx1 = (idx1 + 1) & 0xff; + first = cache[idx1]; + if (first == null) + { + first = cache[idx1] = new ASN1ObjectIdentifier[128]; + } + + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + idx2 = (idx2 + 1) & 0x7f; + possibleMatch = first[idx2]; + if (possibleMatch == null) + { + return first[idx2] = new ASN1ObjectIdentifier(enc); + } + } + + if (Arrays.areEqual(enc, possibleMatch.getBody())) + { + return possibleMatch; + } + + return new ASN1ObjectIdentifier(enc); } /** @@ -31,8 +439,9 @@ public class ASN1ObjectIdentifier /** * Return true if this oid is an extension of the passed in branch, stem. + * * @param stem the arc or branch that is a possible parent. - * @return true if the branch is on the passed in stem, false otherwise. + * @return true if the branch is on the passed in stem, false otherwise. */ public boolean on(ASN1ObjectIdentifier stem) { diff --git a/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java b/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java index 8b8d2260..378ea359 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java +++ b/core/src/main/java/org/bouncycastle/asn1/DERBoolean.java @@ -1,179 +1,22 @@ package org.bouncycastle.asn1; -import java.io.IOException; - -import org.bouncycastle.util.Arrays; - +/** + * @deprecated use ASN1Boolean + */ public class DERBoolean - extends ASN1Primitive + extends ASN1Boolean { - private static final byte[] TRUE_VALUE = new byte[] { (byte)0xff }; - private static final byte[] FALSE_VALUE = new byte[] { 0 }; - - private byte[] value; - - public static final ASN1Boolean FALSE = new ASN1Boolean(false); - public static final ASN1Boolean TRUE = new ASN1Boolean(true); - - - /** - * return a boolean from the passed in object. - * - * @exception IllegalArgumentException if the object cannot be converted. - */ - public static ASN1Boolean getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1Boolean) - { - return (ASN1Boolean)obj; - } - - if (obj instanceof DERBoolean) - { - return ((DERBoolean)obj).isTrue() ? DERBoolean.TRUE : DERBoolean.FALSE; - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - - /** - * return a ASN1Boolean from the passed in boolean. - */ - public static ASN1Boolean getInstance( - boolean value) - { - return (value ? TRUE : FALSE); - } - - /** - * return a ASN1Boolean from the passed in boolean. - */ - public static ASN1Boolean getInstance( - int value) - { - return (value != 0 ? TRUE : FALSE); - } - - /** - * return a Boolean from a tagged object. - * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @exception IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1Boolean getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Primitive o = obj.getObject(); - - if (explicit || o instanceof DERBoolean) - { - return getInstance(o); - } - else - { - return ASN1Boolean.fromOctetString(((ASN1OctetString)o).getOctets()); - } - } - - DERBoolean( - byte[] value) - { - if (value.length != 1) - { - throw new IllegalArgumentException("byte value should have 1 byte in it"); - } - - if (value[0] == 0) - { - this.value = FALSE_VALUE; - } - else if (value[0] == 0xff) - { - this.value = TRUE_VALUE; - } - else - { - this.value = Arrays.clone(value); - } - } - /** * @deprecated use getInstance(boolean) method. * @param value */ - public DERBoolean( - boolean value) - { - this.value = (value) ? TRUE_VALUE : FALSE_VALUE; - } - - public boolean isTrue() - { - return (value[0] != 0); - } - - boolean isConstructed() - { - return false; - } - - int encodedLength() + public DERBoolean(boolean value) { - return 3; + super(value); } - void encode( - ASN1OutputStream out) - throws IOException + DERBoolean(byte[] value) { - out.writeEncoded(BERTags.BOOLEAN, value); - } - - protected boolean asn1Equals( - ASN1Primitive o) - { - if ((o == null) || !(o instanceof DERBoolean)) - { - return false; - } - - return (value[0] == ((DERBoolean)o).value[0]); - } - - public int hashCode() - { - return value[0]; - } - - - public String toString() - { - return (value[0] != 0) ? "TRUE" : "FALSE"; - } - - static ASN1Boolean fromOctetString(byte[] value) - { - if (value.length != 1) - { - throw new IllegalArgumentException("BOOLEAN value should have 1 byte in it"); - } - - if (value[0] == 0) - { - return FALSE; - } - else if (value[0] == 0xff) - { - return TRUE; - } - else - { - return new ASN1Boolean(value); - } + super(value); } } diff --git a/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java b/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java index 9b1ef55c..879a01ca 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java +++ b/core/src/main/java/org/bouncycastle/asn1/DEREnumerated.java @@ -1,170 +1,25 @@ package org.bouncycastle.asn1; -import java.io.IOException; import java.math.BigInteger; -import org.bouncycastle.util.Arrays; - /** - * Use ASN1Enumerated instead of this. + * @deprecated Use ASN1Enumerated instead of this. */ public class DEREnumerated - extends ASN1Primitive + extends ASN1Enumerated { - byte[] bytes; - - /** - * return an integer from the passed in object - * - * @exception IllegalArgumentException if the object cannot be converted. - */ - public static ASN1Enumerated getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1Enumerated) - { - return (ASN1Enumerated)obj; - } - - if (obj instanceof DEREnumerated) - { - return new ASN1Enumerated(((DEREnumerated)obj).getValue()); - } - - if (obj instanceof byte[]) - { - try - { - return (ASN1Enumerated)fromByteArray((byte[])obj); - } - catch (Exception e) - { - throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); - } - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - - /** - * return an Enumerated from a tagged object. - * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @exception IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1Enumerated getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Primitive o = obj.getObject(); - - if (explicit || o instanceof DEREnumerated) - { - return getInstance(o); - } - else - { - return fromOctetString(((ASN1OctetString)o).getOctets()); - } - } - - /** - * @deprecated use ASN1Enumerated - */ - public DEREnumerated( - int value) - { - bytes = BigInteger.valueOf(value).toByteArray(); - } - - /** - * @deprecated use ASN1Enumerated - */ - public DEREnumerated( - BigInteger value) - { - bytes = value.toByteArray(); - } - - /** - * @deprecated use ASN1Enumerated - */ - public DEREnumerated( - byte[] bytes) - { - this.bytes = bytes; - } - - public BigInteger getValue() - { - return new BigInteger(bytes); - } - - boolean isConstructed() - { - return false; - } - - int encodedLength() - { - return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; - } - - void encode( - ASN1OutputStream out) - throws IOException + DEREnumerated(byte[] bytes) { - out.writeEncoded(BERTags.ENUMERATED, bytes); + super(bytes); } - - boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DEREnumerated)) - { - return false; - } - - DEREnumerated other = (DEREnumerated)o; - return Arrays.areEqual(this.bytes, other.bytes); - } - - public int hashCode() + public DEREnumerated(BigInteger value) { - return Arrays.hashCode(bytes); + super(value); } - private static ASN1Enumerated[] cache = new ASN1Enumerated[12]; - - static ASN1Enumerated fromOctetString(byte[] enc) + public DEREnumerated(int value) { - if (enc.length > 1) - { - return new ASN1Enumerated(Arrays.clone(enc)); - } - - if (enc.length == 0) - { - throw new IllegalArgumentException("ENUMERATED has zero length"); - } - int value = enc[0] & 0xff; - - if (value >= cache.length) - { - return new ASN1Enumerated(Arrays.clone(enc)); - } - - ASN1Enumerated possibleMatch = cache[value]; - - if (possibleMatch == null) - { - possibleMatch = cache[value] = new ASN1Enumerated(Arrays.clone(enc)); - } - - return possibleMatch; + super(value); } } diff --git a/core/src/main/java/org/bouncycastle/asn1/DERInteger.java b/core/src/main/java/org/bouncycastle/asn1/DERInteger.java index 57cc84a7..d2e850f3 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DERInteger.java +++ b/core/src/main/java/org/bouncycastle/asn1/DERInteger.java @@ -1,160 +1,30 @@ package org.bouncycastle.asn1; -import java.io.IOException; import java.math.BigInteger; -import org.bouncycastle.util.Arrays; - /** - * Use ASN1Integer instead of this, + * @deprecated Use ASN1Integer instead of this, */ public class DERInteger - extends ASN1Primitive + extends ASN1Integer { - byte[] bytes; - - /** - * return an integer from the passed in object - * - * @exception IllegalArgumentException if the object cannot be converted. - */ - public static ASN1Integer getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1Integer) - { - return (ASN1Integer)obj; - } - if (obj instanceof DERInteger) - { - return new ASN1Integer((((DERInteger)obj).getValue())); - } - - if (obj instanceof byte[]) - { - try - { - return (ASN1Integer)fromByteArray((byte[])obj); - } - catch (Exception e) - { - throw new IllegalArgumentException("encoding error in getInstance: " + e.toString()); - } - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - /** - * return an Integer from a tagged object. + * Constructor from a byte array containing a signed representation of the number. * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @exception IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1Integer getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Primitive o = obj.getObject(); - - if (explicit || o instanceof DERInteger) - { - return getInstance(o); - } - else - { - return new ASN1Integer(ASN1OctetString.getInstance(obj.getObject()).getOctets()); - } - } - - /** - * @deprecated use ASN1Integer constructor - */ - public DERInteger( - long value) - { - bytes = BigInteger.valueOf(value).toByteArray(); - } - - /** - * @deprecated use ASN1Integer constructor + * @param bytes a byte array containing the signed number.A copy is made of the byte array. */ - public DERInteger( - BigInteger value) + public DERInteger(byte[] bytes) { - bytes = value.toByteArray(); + super(bytes, true); } - /** - * @deprecated use ASN1Integer constructor - */ - public DERInteger( - byte[] bytes) + public DERInteger(BigInteger value) { - this.bytes = bytes; - } - - public BigInteger getValue() - { - return new BigInteger(bytes); - } - - /** - * in some cases positive values get crammed into a space, - * that's not quite big enough... - */ - public BigInteger getPositiveValue() - { - return new BigInteger(1, bytes); - } - - boolean isConstructed() - { - return false; - } - - int encodedLength() - { - return 1 + StreamUtil.calculateBodyLength(bytes.length) + bytes.length; - } - - void encode( - ASN1OutputStream out) - throws IOException - { - out.writeEncoded(BERTags.INTEGER, bytes); - } - - public int hashCode() - { - int value = 0; - - for (int i = 0; i != bytes.length; i++) - { - value ^= (bytes[i] & 0xff) << (i % 4); - } - - return value; - } - - boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DERInteger)) - { - return false; - } - - DERInteger other = (DERInteger)o; - - return Arrays.areEqual(bytes, other.bytes); + super(value); } - public String toString() + public DERInteger(long value) { - return getValue().toString(); + super(value); } } diff --git a/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java index 3d4d04c1..acb2ada6 100644 --- a/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java +++ b/core/src/main/java/org/bouncycastle/asn1/DERObjectIdentifier.java @@ -1,446 +1,24 @@ package org.bouncycastle.asn1; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; - -import org.bouncycastle.util.Arrays; - /** - * Use ASN1ObjectIdentifier instead of this, + * + * @deprecated Use ASN1ObjectIdentifier instead of this, */ public class DERObjectIdentifier - extends ASN1Primitive + extends ASN1ObjectIdentifier { - String identifier; - - private byte[] body; - - /** - * return an OID from the passed in object - * - * @throws IllegalArgumentException if the object cannot be converted. - */ - public static ASN1ObjectIdentifier getInstance( - Object obj) - { - if (obj == null || obj instanceof ASN1ObjectIdentifier) - { - return (ASN1ObjectIdentifier)obj; - } - - if (obj instanceof DERObjectIdentifier) - { - return new ASN1ObjectIdentifier(((DERObjectIdentifier)obj).getId()); - } - - if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) - { - return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); - } - - if (obj instanceof byte[]) - { - byte[] enc = (byte[])obj; - if (enc[0] == BERTags.OBJECT_IDENTIFIER) - { - try - { - return (ASN1ObjectIdentifier)fromByteArray(enc); - } - catch (IOException e) - { - throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); - } - } - else - { // TODO: this really shouldn't be supported here... - return ASN1ObjectIdentifier.fromOctetString((byte[])obj); - } - } - - throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName()); - } - - /** - * return an Object Identifier from a tagged object. - * - * @param obj the tagged object holding the object we want - * @param explicit true if the object is meant to be explicitly - * tagged false otherwise. - * @throws IllegalArgumentException if the tagged object cannot - * be converted. - */ - public static ASN1ObjectIdentifier getInstance( - ASN1TaggedObject obj, - boolean explicit) - { - ASN1Primitive o = obj.getObject(); - - if (explicit || o instanceof DERObjectIdentifier) - { - return getInstance(o); - } - else - { - return ASN1ObjectIdentifier.fromOctetString(ASN1OctetString.getInstance(obj.getObject()).getOctets()); - } - } - - private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7f; - - DERObjectIdentifier( - byte[] bytes) + public DERObjectIdentifier(String identifier) { - StringBuffer objId = new StringBuffer(); - long value = 0; - BigInteger bigValue = null; - boolean first = true; - - for (int i = 0; i != bytes.length; i++) - { - int b = bytes[i] & 0xff; - - if (value <= LONG_LIMIT) - { - value += (b & 0x7f); - if ((b & 0x80) == 0) // end of number reached - { - if (first) - { - if (value < 40) - { - objId.append('0'); - } - else if (value < 80) - { - objId.append('1'); - value -= 40; - } - else - { - objId.append('2'); - value -= 80; - } - first = false; - } - - objId.append('.'); - objId.append(value); - value = 0; - } - else - { - value <<= 7; - } - } - else - { - if (bigValue == null) - { - bigValue = BigInteger.valueOf(value); - } - bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f)); - if ((b & 0x80) == 0) - { - if (first) - { - objId.append('2'); - bigValue = bigValue.subtract(BigInteger.valueOf(80)); - first = false; - } - - objId.append('.'); - objId.append(bigValue); - bigValue = null; - value = 0; - } - else - { - bigValue = bigValue.shiftLeft(7); - } - } - } - - this.identifier = objId.toString(); - this.body = Arrays.clone(bytes); + super(identifier); } - /** - * @deprecated use ASN1ObjectIdentifier constructor. - */ - public DERObjectIdentifier( - String identifier) + DERObjectIdentifier(byte[] bytes) { - if (identifier == null) - { - throw new IllegalArgumentException("'identifier' cannot be null"); - } - if (!isValidIdentifier(identifier)) - { - throw new IllegalArgumentException("string " + identifier + " not an OID"); - } - - this.identifier = identifier; + super(bytes); } - DERObjectIdentifier(DERObjectIdentifier oid, String branchID) + DERObjectIdentifier(ASN1ObjectIdentifier oid, String branch) { - if (!isValidBranchID(branchID, 0)) - { - throw new IllegalArgumentException("string " + branchID + " not a valid OID branch"); - } - - this.identifier = oid.getId() + "." + branchID; - } - - public String getId() - { - return identifier; - } - - private void writeField( - ByteArrayOutputStream out, - long fieldValue) - { - byte[] result = new byte[9]; - int pos = 8; - result[pos] = (byte)((int)fieldValue & 0x7f); - while (fieldValue >= (1L << 7)) - { - fieldValue >>= 7; - result[--pos] = (byte)((int)fieldValue & 0x7f | 0x80); - } - out.write(result, pos, 9 - pos); - } - - private void writeField( - ByteArrayOutputStream out, - BigInteger fieldValue) - { - int byteCount = (fieldValue.bitLength() + 6) / 7; - if (byteCount == 0) - { - out.write(0); - } - else - { - BigInteger tmpValue = fieldValue; - byte[] tmp = new byte[byteCount]; - for (int i = byteCount - 1; i >= 0; i--) - { - tmp[i] = (byte)((tmpValue.intValue() & 0x7f) | 0x80); - tmpValue = tmpValue.shiftRight(7); - } - tmp[byteCount - 1] &= 0x7f; - out.write(tmp, 0, tmp.length); - } - } - - private void doOutput(ByteArrayOutputStream aOut) - { - OIDTokenizer tok = new OIDTokenizer(identifier); - int first = Integer.parseInt(tok.nextToken()) * 40; - - String secondToken = tok.nextToken(); - if (secondToken.length() <= 18) - { - writeField(aOut, first + Long.parseLong(secondToken)); - } - else - { - writeField(aOut, new BigInteger(secondToken).add(BigInteger.valueOf(first))); - } - - while (tok.hasMoreTokens()) - { - String token = tok.nextToken(); - if (token.length() <= 18) - { - writeField(aOut, Long.parseLong(token)); - } - else - { - writeField(aOut, new BigInteger(token)); - } - } - } - - protected synchronized byte[] getBody() - { - if (body == null) - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - doOutput(bOut); - - body = bOut.toByteArray(); - } - - return body; - } - - boolean isConstructed() - { - return false; - } - - int encodedLength() - throws IOException - { - int length = getBody().length; - - return 1 + StreamUtil.calculateBodyLength(length) + length; - } - - void encode( - ASN1OutputStream out) - throws IOException - { - byte[] enc = getBody(); - - out.write(BERTags.OBJECT_IDENTIFIER); - out.writeLength(enc.length); - out.write(enc); - } - - public int hashCode() - { - return identifier.hashCode(); - } - - boolean asn1Equals( - ASN1Primitive o) - { - if (!(o instanceof DERObjectIdentifier)) - { - return false; - } - - return identifier.equals(((DERObjectIdentifier)o).identifier); - } - - public String toString() - { - return getId(); - } - - private static boolean isValidBranchID( - String branchID, int start) - { - boolean periodAllowed = false; - - int pos = branchID.length(); - while (--pos >= start) - { - char ch = branchID.charAt(pos); - - // TODO Leading zeroes? - if ('0' <= ch && ch <= '9') - { - periodAllowed = true; - continue; - } - - if (ch == '.') - { - if (!periodAllowed) - { - return false; - } - - periodAllowed = false; - continue; - } - - return false; - } - - return periodAllowed; - } - - private static boolean isValidIdentifier( - String identifier) - { - if (identifier.length() < 3 || identifier.charAt(1) != '.') - { - return false; - } - - char first = identifier.charAt(0); - if (first < '0' || first > '2') - { - return false; - } - - return isValidBranchID(identifier, 2); - } - - private static ASN1ObjectIdentifier[][] cache = new ASN1ObjectIdentifier[256][]; - - static ASN1ObjectIdentifier fromOctetString(byte[] enc) - { - if (enc.length < 3) - { - return new ASN1ObjectIdentifier(enc); - } - - int idx1 = enc[enc.length - 2] & 0xff; - // in this case top bit is always zero - int idx2 = enc[enc.length - 1] & 0x7f; - - ASN1ObjectIdentifier possibleMatch; - - synchronized (cache) - { - ASN1ObjectIdentifier[] first = cache[idx1]; - if (first == null) - { - first = cache[idx1] = new ASN1ObjectIdentifier[128]; - } - - possibleMatch = first[idx2]; - if (possibleMatch == null) - { - return first[idx2] = new ASN1ObjectIdentifier(enc); - } - - if (Arrays.areEqual(enc, possibleMatch.getBody())) - { - return possibleMatch; - } - - idx1 = (idx1 + 1) & 0xff; - first = cache[idx1]; - if (first == null) - { - first = cache[idx1] = new ASN1ObjectIdentifier[128]; - } - - possibleMatch = first[idx2]; - if (possibleMatch == null) - { - return first[idx2] = new ASN1ObjectIdentifier(enc); - } - - if (Arrays.areEqual(enc, possibleMatch.getBody())) - { - return possibleMatch; - } - - idx2 = (idx2 + 1) & 0x7f; - possibleMatch = first[idx2]; - if (possibleMatch == null) - { - return first[idx2] = new ASN1ObjectIdentifier(enc); - } - } - - if (Arrays.areEqual(enc, possibleMatch.getBody())) - { - return possibleMatch; - } - - return new ASN1ObjectIdentifier(enc); + super(oid, branch); } } diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java b/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java index 066cf693..8c487433 100644 --- a/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java +++ b/core/src/main/java/org/bouncycastle/asn1/cms/Attribute.java @@ -7,7 +7,6 @@ import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; /** @@ -73,17 +72,6 @@ public class Attribute attrValues = (ASN1Set)seq.getObjectAt(1); } - /** - * @deprecated use ASN1ObjectIdentifier - */ - public Attribute( - DERObjectIdentifier attrType, - ASN1Set attrValues) - { - this.attrType = new ASN1ObjectIdentifier(attrType.getId()); - this.attrValues = attrValues; - } - public Attribute( ASN1ObjectIdentifier attrType, ASN1Set attrValues) diff --git a/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java b/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java index 02b6cc1e..3b8e0bed 100644 --- a/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java +++ b/core/src/main/java/org/bouncycastle/asn1/cms/AttributeTable.java @@ -8,7 +8,6 @@ import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Set; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSet; /** @@ -91,14 +90,6 @@ public class AttributeTable } /** - * @deprecated use ASN1ObjectIdentifier - */ - public Attribute get(DERObjectIdentifier oid) - { - return get(new ASN1ObjectIdentifier(oid.getId())); - } - - /** * Return the first attribute matching the OBJECT IDENTIFIER oid. * * @param oid type of attribute required. @@ -117,14 +108,6 @@ public class AttributeTable return (Attribute)value; } - /** - * @deprecated use ASN1ObjectIdentifier - */ - public ASN1EncodableVector getAll(DERObjectIdentifier oid) - { - return getAll(new ASN1ObjectIdentifier(oid.getId())); - } - /** * Return all the attributes matching the OBJECT IDENTIFIER oid. The vector will be * empty if there are no attributes of the required type present. diff --git a/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java b/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java index 93d9d0c8..462d9685 100644 --- a/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java +++ b/core/src/main/java/org/bouncycastle/asn1/ess/ContentHints.java @@ -6,7 +6,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERUTF8String; @@ -47,25 +46,6 @@ public class ContentHints } } - /** - * @deprecated use ASN1ObjectIdentifier - */ - public ContentHints( - DERObjectIdentifier contentType) - { - this(new ASN1ObjectIdentifier(contentType.getId())); - } - - /** - * @deprecated use ASN1ObjectIdentifier - */ - public ContentHints( - DERObjectIdentifier contentType, - DERUTF8String contentDescription) - { - this(new ASN1ObjectIdentifier(contentType.getId()), contentDescription); - } - public ContentHints( ASN1ObjectIdentifier contentType) { diff --git a/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java b/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java index c6a2965b..d654d032 100644 --- a/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java +++ b/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java @@ -23,7 +23,7 @@ public class ElGamalParameter this.g = new ASN1Integer(g); } - public ElGamalParameter( + private ElGamalParameter( ASN1Sequence seq) { Enumeration e = seq.getObjects(); @@ -32,6 +32,20 @@ public class ElGamalParameter g = (ASN1Integer)e.nextElement(); } + public static ElGamalParameter getInstance(Object o) + { + if (o instanceof ElGamalParameter) + { + return (ElGamalParameter)o; + } + else if (o != null) + { + return new ElGamalParameter(ASN1Sequence.getInstance(o)); + } + + return null; + } + public BigInteger getP() { return p.getPositiveValue(); diff --git a/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java index 1ba3dbea..450fd703 100644 --- a/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java +++ b/core/src/main/java/org/bouncycastle/asn1/sec/SECNamedCurves.java @@ -10,6 +10,8 @@ import org.bouncycastle.asn1.x9.X9ECParametersHolder; import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism; +import org.bouncycastle.math.ec.endo.GLVTypeBParameters; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; @@ -20,6 +22,11 @@ public class SECNamedCurves return curve; } + private static ECCurve configureCurveGLV(ECCurve c, GLVTypeBParameters p) + { + return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create(); + } + private static BigInteger fromHex( String hex) { @@ -145,7 +152,20 @@ public class SECNamedCurves BigInteger n = fromHex("0100000000000000000001B8FA16DFAB9ACA16B6B3"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16), + new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16), + new BigInteger[]{ + new BigInteger("9162fbe73984472a0a9e", 16), + new BigInteger("-96341f1138933bc2f505", 16) }, + new BigInteger[]{ + new BigInteger("127971af8721782ecffa3", 16), + new BigInteger("9162fbe73984472a0a9e", 16) }, + new BigInteger("48b17df39cc22395054e8", 16), + new BigInteger("4b1a0f889c499de17a820", 16), + 163); + + ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); // ECPoint G = curve.decodePoint(Hex.decode("02" // + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -223,7 +243,20 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16), + new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16), + new BigInteger[]{ + new BigInteger("71169be7330b3038edb025f1", 16), + new BigInteger("-b3fb3400dec5c4adceb8655c", 16) }, + new BigInteger[]{ + new BigInteger("12511cfe811d0f4e6bc688b4d", 16), + new BigInteger("71169be7330b3038edb025f1", 16) }, + new BigInteger("1c45a6f9ccc2cc0e3b6c097c7", 16), + new BigInteger("2cfecd0037b1712b73ae19575", 16), + 194); + + ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -275,7 +308,20 @@ public class SECNamedCurves BigInteger n = fromHex("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16), + new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16), + new BigInteger[]{ + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16), + new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) }, + new BigInteger[]{ + new BigInteger("1243ae1b4d71613bc9f780a03690e", 16), + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) }, + new BigInteger("35c6783ea653ae444abeceb382c82", 16), + new BigInteger("5c56f89bc5375b9a04fd364e31bdd", 16), + 227); + + ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); //ECPoint G = curve.decodePoint(Hex.decode("03" //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C")); ECPoint G = curve.decodePoint(Hex.decode("04" @@ -327,7 +373,20 @@ public class SECNamedCurves BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"); BigInteger h = BigInteger.valueOf(1); - ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16), + new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16), + new BigInteger[]{ + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16), + new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) }, + new BigInteger[]{ + new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16), + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) }, + new BigInteger("c21b48869f51af37a1b243924a13ac55", 16), + new BigInteger("3910dfb58043a20a1bd51fea42aff9311", 16), + 258); + + ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); //ECPoint G = curve.decodePoint(Hex.decode("02" //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")); ECPoint G = curve.decodePoint(Hex.decode("04" diff --git a/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java b/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java index 4560f647..8221e182 100644 --- a/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java +++ b/core/src/main/java/org/bouncycastle/asn1/util/ASN1Dump.java @@ -3,7 +3,9 @@ package org.bouncycastle.asn1.util; import java.io.IOException; import java.util.Enumeration; +import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; @@ -12,7 +14,6 @@ import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.BERApplicationSpecific; -import org.bouncycastle.asn1.BERConstructedOctetString; import org.bouncycastle.asn1.BEROctetString; import org.bouncycastle.asn1.BERSequence; import org.bouncycastle.asn1.BERSet; @@ -21,8 +22,6 @@ import org.bouncycastle.asn1.BERTags; import org.bouncycastle.asn1.DERApplicationSpecific; import org.bouncycastle.asn1.DERBMPString; import org.bouncycastle.asn1.DERBitString; -import org.bouncycastle.asn1.DERBoolean; -import org.bouncycastle.asn1.DEREnumerated; import org.bouncycastle.asn1.DERExternal; import org.bouncycastle.asn1.DERGeneralizedTime; import org.bouncycastle.asn1.DERIA5String; @@ -193,9 +192,9 @@ public class ASN1Dump { buf.append(indent + "ObjectIdentifier(" + ((ASN1ObjectIdentifier)obj).getId() + ")" + nl); } - else if (obj instanceof DERBoolean) + else if (obj instanceof ASN1Boolean) { - buf.append(indent + "Boolean(" + ((DERBoolean)obj).isTrue() + ")" + nl); + buf.append(indent + "Boolean(" + ((ASN1Boolean)obj).isTrue() + ")" + nl); } else if (obj instanceof ASN1Integer) { @@ -254,9 +253,9 @@ public class ASN1Dump { buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl)); } - else if (obj instanceof DEREnumerated) + else if (obj instanceof ASN1Enumerated) { - DEREnumerated en = (DEREnumerated) obj; + ASN1Enumerated en = (ASN1Enumerated) obj; buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl); } else if (obj instanceof DERExternal) diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java new file mode 100644 index 00000000..a411f9ca --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java @@ -0,0 +1,188 @@ +package org.bouncycastle.asn1.x500.style; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; + +import org.bouncycastle.asn1.ASN1Encodable; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.DERUTF8String; +import org.bouncycastle.asn1.x500.AttributeTypeAndValue; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameStyle; + +/** + * This class provides some default behavior and common implementation for a + * X500NameStyle. It should be easily extendible to support implementing the + * desired X500NameStyle. + */ +public abstract class AbstractX500NameStyle + implements X500NameStyle +{ + + /** + * Tool function to shallow copy a Hashtable. + * + * @param paramsMap table to copy + * @return the copy of the table + */ + public static Hashtable copyHashTable(Hashtable paramsMap) + { + Hashtable newTable = new Hashtable(); + + Enumeration keys = paramsMap.keys(); + while (keys.hasMoreElements()) + { + Object key = keys.nextElement(); + newTable.put(key, paramsMap.get(key)); + } + + return newTable; + } + + private int calcHashCode(ASN1Encodable enc) + { + String value = IETFUtils.valueToString(enc); + value = IETFUtils.canonicalize(value); + return value.hashCode(); + } + + public int calculateHashCode(X500Name name) + { + int hashCodeValue = 0; + RDN[] rdns = name.getRDNs(); + + // this needs to be order independent, like equals + for (int i = 0; i != rdns.length; i++) + { + if (rdns[i].isMultiValued()) + { + AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); + + for (int j = 0; j != atv.length; j++) + { + hashCodeValue ^= atv[j].getType().hashCode(); + hashCodeValue ^= calcHashCode(atv[j].getValue()); + } + } + else + { + hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); + hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); + } + } + + return hashCodeValue; + } + + + /** + * For all string values starting with '#' is assumed, that these are + * already valid ASN.1 objects encoded in hex. + * <p/> + * All other string values are send to + * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}. + * <p/> + * Subclasses should overwrite + * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)} + * to change the encoding of specific types. + */ + public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) + { + if (value.length() != 0 && value.charAt(0) == '#') + { + try + { + return IETFUtils.valueFromHexString(value, 1); + } + catch (IOException e) + { + throw new RuntimeException("can't recode value for oid " + oid.getId()); + } + } + + if (value.length() != 0 && value.charAt(0) == '\\') + { + value = value.substring(1); + } + + return encodeStringValue(oid, value); + } + + /** + * Encoded every value into a UTF8String. + * <p/> + * Subclasses should overwrite + * this method to change the encoding of specific types. + * + * @param oid of the value + * @param value to encode + * @return a the value encoded into a ASN.1 object. Never returns <code>null</code>. + */ + protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, String value) + { + return new DERUTF8String(value); + } + + public boolean areEqual(X500Name name1, X500Name name2) + { + RDN[] rdns1 = name1.getRDNs(); + RDN[] rdns2 = name2.getRDNs(); + + if (rdns1.length != rdns2.length) + { + return false; + } + + boolean reverse = false; + + if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) + { + reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward + } + + for (int i = 0; i != rdns1.length; i++) + { + if (!foundMatch(reverse, rdns1[i], rdns2)) + { + return false; + } + } + + return true; + } + + private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) + { + if (reverse) + { + for (int i = possRDNs.length - 1; i >= 0; i--) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + else + { + for (int i = 0; i != possRDNs.length; i++) + { + if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) + { + possRDNs[i] = null; + return true; + } + } + } + + return false; + } + + protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) + { + return IETFUtils.rDNAreEqual(rdn1, rdn2); + } +} diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java index 68421821..dc1cc366 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/BCStyle.java @@ -1,7 +1,5 @@ package org.bouncycastle.asn1.x500.style; -import java.io.IOException; -import java.util.Enumeration; import java.util.Hashtable; import org.bouncycastle.asn1.ASN1Encodable; @@ -9,16 +7,14 @@ import org.bouncycastle.asn1.ASN1GeneralizedTime; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DERPrintableString; -import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; -import org.bouncycastle.asn1.x500.AttributeTypeAndValue; import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500NameStyle; import org.bouncycastle.asn1.x509.X509ObjectIdentifiers; public class BCStyle - implements X500NameStyle + extends AbstractX500NameStyle { /** * country code - StringType(SIZE(2)) @@ -286,41 +282,25 @@ public class BCStyle defaultLookUp = copyHashTable(DefaultLookUp); } - public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) - { - if (value.length() != 0 && value.charAt(0) == '#') + + @Override + protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, + String value) { + if (oid.equals(EmailAddress) || oid.equals(DC)) { - try - { - return IETFUtils.valueFromHexString(value, 1); - } - catch (IOException e) - { - throw new RuntimeException("can't recode value for oid " + oid.getId()); - } + return new DERIA5String(value); } - else + else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility) { - if (value.length() != 0 && value.charAt(0) == '\\') - { - value = value.substring(1); - } - if (oid.equals(EmailAddress) || oid.equals(DC)) - { - return new DERIA5String(value); - } - else if (oid.equals(DATE_OF_BIRTH)) // accept time string as well as # (for compatibility) - { - return new ASN1GeneralizedTime(value); - } - else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER) - || oid.equals(TELEPHONE_NUMBER)) - { - return new DERPrintableString(value); - } + return new ASN1GeneralizedTime(value); } - - return new DERUTF8String(value); + else if (oid.equals(C) || oid.equals(SN) || oid.equals(DN_QUALIFIER) + || oid.equals(TELEPHONE_NUMBER)) + { + return new DERPrintableString(value); + } + + return super.encodeStringValue(oid, value); } public String oidToDisplayName(ASN1ObjectIdentifier oid) @@ -338,109 +318,11 @@ public class BCStyle return IETFUtils.decodeAttrName(attrName, defaultLookUp); } - public boolean areEqual(X500Name name1, X500Name name2) - { - RDN[] rdns1 = name1.getRDNs(); - RDN[] rdns2 = name2.getRDNs(); - - if (rdns1.length != rdns2.length) - { - return false; - } - - boolean reverse = false; - - if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) - { - reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward - } - - for (int i = 0; i != rdns1.length; i++) - { - if (!foundMatch(reverse, rdns1[i], rdns2)) - { - return false; - } - } - - return true; - } - - private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) - { - if (reverse) - { - for (int i = possRDNs.length - 1; i >= 0; i--) - { - if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) - { - possRDNs[i] = null; - return true; - } - } - } - else - { - for (int i = 0; i != possRDNs.length; i++) - { - if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) - { - possRDNs[i] = null; - return true; - } - } - } - - return false; - } - - protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) - { - return IETFUtils.rDNAreEqual(rdn1, rdn2); - } - public RDN[] fromString(String dirName) { return IETFUtils.rDNsFromString(dirName, this); } - public int calculateHashCode(X500Name name) - { - int hashCodeValue = 0; - RDN[] rdns = name.getRDNs(); - - // this needs to be order independent, like equals - for (int i = 0; i != rdns.length; i++) - { - if (rdns[i].isMultiValued()) - { - AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); - - for (int j = 0; j != atv.length; j++) - { - hashCodeValue ^= atv[j].getType().hashCode(); - hashCodeValue ^= calcHashCode(atv[j].getValue()); - } - } - else - { - hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); - hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); - } - } - - return hashCodeValue; - } - - private int calcHashCode(ASN1Encodable enc) - { - String value = IETFUtils.valueToString(enc); - - value = IETFUtils.canonicalize(value); - - return value.hashCode(); - } - public String toString(X500Name name) { StringBuffer buf = new StringBuffer(); @@ -465,17 +347,5 @@ public class BCStyle return buf.toString(); } - private static Hashtable copyHashTable(Hashtable paramsMap) - { - Hashtable newTable = new Hashtable(); - Enumeration keys = paramsMap.keys(); - while (keys.hasMoreElements()) - { - Object key = keys.nextElement(); - newTable.put(key, paramsMap.get(key)); - } - - return newTable; - } } diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java index 8c92257e..cc6a4281 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/RFC4519Style.java @@ -1,21 +1,17 @@ package org.bouncycastle.asn1.x500.style; -import java.io.IOException; -import java.util.Enumeration; import java.util.Hashtable; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DERPrintableString; -import org.bouncycastle.asn1.DERUTF8String; -import org.bouncycastle.asn1.x500.AttributeTypeAndValue; import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x500.X500NameStyle; public class RFC4519Style - implements X500NameStyle + extends AbstractX500NameStyle { public static final ASN1ObjectIdentifier businessCategory = new ASN1ObjectIdentifier("2.5.4.15"); public static final ASN1ObjectIdentifier c = new ASN1ObjectIdentifier("2.5.4.6"); @@ -179,37 +175,20 @@ public class RFC4519Style defaultLookUp = copyHashTable(DefaultLookUp); } - public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value) - { - if (value.length() != 0 && value.charAt(0) == '#') + @Override + protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, + String value) { + if (oid.equals(dc)) { - try - { - return IETFUtils.valueFromHexString(value, 1); - } - catch (IOException e) - { - throw new RuntimeException("can't recode value for oid " + oid.getId()); - } + return new DERIA5String(value); } - else + else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier) + || oid.equals(telephoneNumber)) { - if (value.length() != 0 && value.charAt(0) == '\\') - { - value = value.substring(1); - } - if (oid.equals(dc)) - { - return new DERIA5String(value); - } - else if (oid.equals(c) || oid.equals(serialNumber) || oid.equals(dnQualifier) - || oid.equals(telephoneNumber)) - { - return new DERPrintableString(value); - } + return new DERPrintableString(value); } - return new DERUTF8String(value); + return super.encodeStringValue(oid, value); } public String oidToDisplayName(ASN1ObjectIdentifier oid) @@ -227,67 +206,6 @@ public class RFC4519Style return IETFUtils.decodeAttrName(attrName, defaultLookUp); } - public boolean areEqual(X500Name name1, X500Name name2) - { - RDN[] rdns1 = name1.getRDNs(); - RDN[] rdns2 = name2.getRDNs(); - - if (rdns1.length != rdns2.length) - { - return false; - } - - boolean reverse = false; - - if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null) - { - reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward - } - - for (int i = 0; i != rdns1.length; i++) - { - if (!foundMatch(reverse, rdns1[i], rdns2)) - { - return false; - } - } - - return true; - } - - private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs) - { - if (reverse) - { - for (int i = possRDNs.length - 1; i >= 0; i--) - { - if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) - { - possRDNs[i] = null; - return true; - } - } - } - else - { - for (int i = 0; i != possRDNs.length; i++) - { - if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i])) - { - possRDNs[i] = null; - return true; - } - } - } - - return false; - } - - protected boolean rdnAreEqual(RDN rdn1, RDN rdn2) - { - return IETFUtils.rDNAreEqual(rdn1, rdn2); - } - // parse backwards public RDN[] fromString(String dirName) { @@ -302,43 +220,6 @@ public class RFC4519Style return res; } - public int calculateHashCode(X500Name name) - { - int hashCodeValue = 0; - RDN[] rdns = name.getRDNs(); - - // this needs to be order independent, like equals - for (int i = 0; i != rdns.length; i++) - { - if (rdns[i].isMultiValued()) - { - AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues(); - - for (int j = 0; j != atv.length; j++) - { - hashCodeValue ^= atv[j].getType().hashCode(); - hashCodeValue ^= calcHashCode(atv[j].getValue()); - } - } - else - { - hashCodeValue ^= rdns[i].getFirst().getType().hashCode(); - hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue()); - } - } - - return hashCodeValue; - } - - private int calcHashCode(ASN1Encodable enc) - { - String value = IETFUtils.valueToString(enc); - - value = IETFUtils.canonicalize(value); - - return value.hashCode(); - } - // convert in reverse public String toString(X500Name name) { @@ -364,17 +245,5 @@ public class RFC4519Style return buf.toString(); } - private static Hashtable copyHashTable(Hashtable paramsMap) - { - Hashtable newTable = new Hashtable(); - - Enumeration keys = paramsMap.keys(); - while (keys.hasMoreElements()) - { - Object key = keys.nextElement(); - newTable.put(key, paramsMap.get(key)); - } - - return newTable; - } + } diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java index 2c8e3fcf..b7e52f22 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java +++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/X500NameTokenizer.java @@ -6,7 +6,7 @@ package org.bouncycastle.asn1.x500.style; * lightweight Java environment don't support classes like * StringTokenizer. */ -class X500NameTokenizer +public class X500NameTokenizer { private String value; private int index; diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java index d250bf1e..bb90030c 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java @@ -8,7 +8,6 @@ import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERNull; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; public class AlgorithmIdentifier @@ -64,30 +63,6 @@ public class AlgorithmIdentifier this.objectId = new ASN1ObjectIdentifier(objectId); } - /** - * @deprecated use ASN1ObjectIdentifier - * @param objectId - */ - public AlgorithmIdentifier( - DERObjectIdentifier objectId) - { - this.objectId = new ASN1ObjectIdentifier(objectId.getId()); - } - - /** - * @deprecated use ASN1ObjectIdentifier - * @param objectId - * @param parameters - */ - public AlgorithmIdentifier( - DERObjectIdentifier objectId, - ASN1Encodable parameters) - { - parametersDefined = true; - this.objectId = new ASN1ObjectIdentifier(objectId.getId()); - this.parameters = parameters; - } - public AlgorithmIdentifier( ASN1ObjectIdentifier objectId, ASN1Encodable parameters) diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java b/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java index 4a16bd4b..ba5ecf1f 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/BasicConstraints.java @@ -9,7 +9,6 @@ import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DERBoolean; import org.bouncycastle.asn1.DERSequence; public class BasicConstraints @@ -59,9 +58,9 @@ public class BasicConstraints } else { - if (seq.getObjectAt(0) instanceof DERBoolean) + if (seq.getObjectAt(0) instanceof ASN1Boolean) { - this.cA = DERBoolean.getInstance(seq.getObjectAt(0)); + this.cA = ASN1Boolean.getInstance(seq.getObjectAt(0)); } else { diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java index f29284d5..93530571 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extension.java @@ -2,11 +2,11 @@ package org.bouncycastle.asn1.x509; import java.io.IOException; +import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.DERBoolean; /** * an object for the elements in the X.509 V3 extension block. @@ -173,7 +173,7 @@ public class X509Extension ASN1OctetString value; public X509Extension( - DERBoolean critical, + ASN1Boolean critical, ASN1OctetString value) { this.critical = critical.isTrue(); diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java index c72e3cc0..5b9ea9e1 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Extensions.java @@ -4,6 +4,7 @@ import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; +import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Object; import org.bouncycastle.asn1.ASN1ObjectIdentifier; @@ -11,8 +12,6 @@ import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; -import org.bouncycastle.asn1.DERBoolean; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DERSequence; /** @@ -259,7 +258,7 @@ public class X509Extensions if (s.size() == 3) { - extensions.put(s.getObjectAt(0), new X509Extension(DERBoolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)))); + extensions.put(s.getObjectAt(0), new X509Extension(ASN1Boolean.getInstance(s.getObjectAt(1)), ASN1OctetString.getInstance(s.getObjectAt(2)))); } else if (s.size() == 2) { @@ -369,17 +368,6 @@ public class X509Extensions * @return the extension if it's present, null otherwise. */ public X509Extension getExtension( - DERObjectIdentifier oid) - { - return (X509Extension)extensions.get(oid); - } - - /** - * @deprecated - * @param oid - * @return - */ - public X509Extension getExtension( ASN1ObjectIdentifier oid) { return (X509Extension)extensions.get(oid); @@ -410,7 +398,7 @@ public class X509Extensions if (ext.isCritical()) { - v.add(DERBoolean.TRUE); + v.add(ASN1Boolean.TRUE); } v.add(ext.getValue()); diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java index 468d1b96..589d512f 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java +++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509ExtensionsGenerator.java @@ -7,7 +7,6 @@ import java.util.Vector; import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encoding; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DEROctetString; /** @@ -29,28 +28,6 @@ public class X509ExtensionsGenerator } /** - * @deprecated use ASN1ObjectIdentifier - */ - public void addExtension( - DERObjectIdentifier oid, - boolean critical, - ASN1Encodable value) - { - addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); - } - - /** - * @deprecated use ASN1ObjectIdentifier - */ - public void addExtension( - DERObjectIdentifier oid, - boolean critical, - byte[] value) - { - addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); - } - - /** * Add an extension with the given oid and the passed in value to be included * in the OCTET STRING associated with the extension. * diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java b/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java index 6a97a48e..509111ad 100644 --- a/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java +++ b/core/src/main/java/org/bouncycastle/asn1/x9/DHDomainParameters.java @@ -1,5 +1,6 @@ package org.bouncycastle.asn1.x9; +import java.math.BigInteger; import java.util.Enumeration; import org.bouncycastle.asn1.ASN1Encodable; @@ -38,6 +39,29 @@ public class DHDomainParameters + obj.getClass().getName()); } + public DHDomainParameters(BigInteger p, BigInteger g, BigInteger q, BigInteger j, + DHValidationParms validationParms) + { + if (p == null) + { + throw new IllegalArgumentException("'p' cannot be null"); + } + if (g == null) + { + throw new IllegalArgumentException("'g' cannot be null"); + } + if (q == null) + { + throw new IllegalArgumentException("'q' cannot be null"); + } + + this.p = new ASN1Integer(p); + this.g = new ASN1Integer(g); + this.q = new ASN1Integer(q); + this.j = new ASN1Integer(j); + this.validationParms = validationParms; + } + public DHDomainParameters(ASN1Integer p, ASN1Integer g, ASN1Integer q, ASN1Integer j, DHValidationParms validationParms) { diff --git a/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java b/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java index 947bc5c4..55d8ba51 100644 --- a/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java +++ b/core/src/main/java/org/bouncycastle/crypto/agreement/kdf/DHKEKGenerator.java @@ -4,7 +4,7 @@ import java.io.IOException; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Encoding; -import org.bouncycastle.asn1.DERObjectIdentifier; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERTaggedObject; @@ -22,7 +22,7 @@ public class DHKEKGenerator { private final Digest digest; - private DERObjectIdentifier algorithm; + private ASN1ObjectIdentifier algorithm; private int keySize; private byte[] z; private byte[] partyAInfo; diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java b/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java index 7da095b0..5bfe96d7 100644 --- a/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java +++ b/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java @@ -1,5 +1,6 @@ package org.bouncycastle.crypto.ec; +import java.math.BigInteger; import java.util.Enumeration; import java.util.Hashtable; @@ -9,11 +10,17 @@ import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ECParametersHolder; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.custom.djb.Curve25519; import org.bouncycastle.math.ec.custom.sec.SecP192K1Curve; import org.bouncycastle.math.ec.custom.sec.SecP192R1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP224K1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP224R1Curve; import org.bouncycastle.math.ec.custom.sec.SecP256K1Curve; import org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; +import org.bouncycastle.math.ec.custom.sec.SecP384R1Curve; import org.bouncycastle.math.ec.custom.sec.SecP521R1Curve; +import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism; +import org.bouncycastle.math.ec.endo.GLVTypeBParameters; import org.bouncycastle.util.Strings; import org.bouncycastle.util.encoders.Hex; @@ -24,6 +31,38 @@ public class CustomNamedCurves return curve; } + private static ECCurve configureCurveGLV(ECCurve c, GLVTypeBParameters p) + { + return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create(); + } + + /* + * curve25519 + */ + static X9ECParametersHolder curve25519 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = null; + ECCurve curve = configureCurve(new Curve25519()); + + /* + * NOTE: Curve25519 was specified in Montgomery form. Rewriting in Weierstrass form + * involves substitution of variables, so the base-point x coordinate is 9 + (486662 / 3). + * + * The Curve25519 paper doesn't say which of the two possible y values the base + * point has. The choice here is guided by language in the Ed25519 paper. + * + * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14) + */ + ECPoint G = curve.decodePoint(Hex.decode("04" + + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A" + + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9")); + + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + /* * secp192k1 */ @@ -32,7 +71,19 @@ public class CustomNamedCurves protected X9ECParameters createParameters() { byte[] S = null; - ECCurve curve = configureCurve(new SecP192K1Curve()); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16), + new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16), + new BigInteger[]{ + new BigInteger("71169be7330b3038edb025f1", 16), + new BigInteger("-b3fb3400dec5c4adceb8655c", 16) }, + new BigInteger[]{ + new BigInteger("12511cfe811d0f4e6bc688b4d", 16), + new BigInteger("71169be7330b3038edb025f1", 16) }, + new BigInteger("1c45a6f9ccc2cc0e3b6c097c7", 16), + new BigInteger("2cfecd0037b1712b73ae19575", 16), + 194); + ECCurve curve = configureCurveGLV(new SecP192K1Curve(), glv); ECPoint G = curve.decodePoint(Hex.decode("04" + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); @@ -57,6 +108,50 @@ public class CustomNamedCurves }; /* + * secp224k1 + */ + static X9ECParametersHolder secp224k1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = null; + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16), + new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16), + new BigInteger[]{ + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16), + new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) }, + new BigInteger[]{ + new BigInteger("1243ae1b4d71613bc9f780a03690e", 16), + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) }, + new BigInteger("35c6783ea653ae444abeceb382c82", 16), + new BigInteger("5c56f89bc5375b9a04fd364e31bdd", 16), + 227); + ECCurve curve = configureCurveGLV(new SecP224K1Curve(), glv); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" + + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* + * secp224r1 + */ + static X9ECParametersHolder secp224r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); + ECCurve curve = configureCurve(new SecP224R1Curve()); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" + + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* * secp256k1 */ static X9ECParametersHolder secp256k1 = new X9ECParametersHolder() @@ -64,7 +159,19 @@ public class CustomNamedCurves protected X9ECParameters createParameters() { byte[] S = null; - ECCurve curve = configureCurve(new SecP256K1Curve()); + GLVTypeBParameters glv = new GLVTypeBParameters( + new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16), + new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16), + new BigInteger[]{ + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16), + new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) }, + new BigInteger[]{ + new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16), + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) }, + new BigInteger("c21b48869f51af37a1b243924a13ac55", 16), + new BigInteger("3910dfb58043a20a1bd51fea42aff9311", 16), + 258); + ECCurve curve = configureCurveGLV(new SecP256K1Curve(), glv); ECPoint G = curve.decodePoint(Hex.decode("04" + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); @@ -89,6 +196,22 @@ public class CustomNamedCurves }; /* + * secp384r1 + */ + static X9ECParametersHolder secp384r1 = new X9ECParametersHolder() + { + protected X9ECParameters createParameters() + { + byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73"); + ECCurve curve = configureCurve(new SecP384R1Curve()); + ECPoint G = curve.decodePoint(Hex.decode("04" + + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" + + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); + return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); + } + }; + + /* * secp521r1 */ static X9ECParametersHolder secp521r1 = new X9ECParametersHolder() @@ -104,34 +227,55 @@ public class CustomNamedCurves } }; - static final Hashtable objIds = new Hashtable(); - static final Hashtable curves = new Hashtable(); - static final Hashtable names = new Hashtable(); + static final Hashtable nameToCurve = new Hashtable(); + static final Hashtable nameToOID = new Hashtable(); + static final Hashtable oidToCurve = new Hashtable(); + static final Hashtable oidToName = new Hashtable(); - static void defineCurve(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) + static void defineCurve(String name, X9ECParametersHolder holder) { - objIds.put(name, oid); - names.put(oid, name); - curves.put(oid, holder); + nameToCurve.put(name, holder); + } + + static void defineCurveWithOID(String name, ASN1ObjectIdentifier oid, X9ECParametersHolder holder) + { + nameToCurve.put(name, holder); + nameToOID.put(name, oid); + oidToName.put(oid, name); + oidToCurve.put(oid, holder); + } + + static void defineCurveAlias(String alias, ASN1ObjectIdentifier oid) + { + alias = Strings.toLowerCase(alias); + nameToOID.put(alias, oid); + nameToCurve.put(alias, oidToCurve.get(oid)); } static { - defineCurve("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1); - defineCurve("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1); - defineCurve("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1); - defineCurve("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1); - defineCurve("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1); + defineCurve("curve25519", curve25519); + + defineCurveWithOID("secp192k1", SECObjectIdentifiers.secp192k1, secp192k1); + defineCurveWithOID("secp192r1", SECObjectIdentifiers.secp192r1, secp192r1); + defineCurveWithOID("secp224k1", SECObjectIdentifiers.secp224k1, secp224k1); + defineCurveWithOID("secp224r1", SECObjectIdentifiers.secp224r1, secp224r1); + defineCurveWithOID("secp256k1", SECObjectIdentifiers.secp256k1, secp256k1); + defineCurveWithOID("secp256r1", SECObjectIdentifiers.secp256r1, secp256r1); + defineCurveWithOID("secp384r1", SECObjectIdentifiers.secp384r1, secp384r1); + defineCurveWithOID("secp521r1", SECObjectIdentifiers.secp521r1, secp521r1); - objIds.put(Strings.toLowerCase("P-192"), SECObjectIdentifiers.secp192r1); - objIds.put(Strings.toLowerCase("P-256"), SECObjectIdentifiers.secp256r1); - objIds.put(Strings.toLowerCase("P-521"), SECObjectIdentifiers.secp521r1); + defineCurveAlias("P-192", SECObjectIdentifiers.secp192r1); + defineCurveAlias("P-224", SECObjectIdentifiers.secp224r1); + defineCurveAlias("P-256", SECObjectIdentifiers.secp256r1); + defineCurveAlias("P-384", SECObjectIdentifiers.secp384r1); + defineCurveAlias("P-521", SECObjectIdentifiers.secp521r1); } public static X9ECParameters getByName(String name) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); - return oid == null ? null : getByOID(oid); + X9ECParametersHolder holder = (X9ECParametersHolder)nameToCurve.get(Strings.toLowerCase(name)); + return holder == null ? null : holder.getParameters(); } /** @@ -143,7 +287,7 @@ public class CustomNamedCurves */ public static X9ECParameters getByOID(ASN1ObjectIdentifier oid) { - X9ECParametersHolder holder = (X9ECParametersHolder)curves.get(oid); + X9ECParametersHolder holder = (X9ECParametersHolder)oidToCurve.get(oid); return holder == null ? null : holder.getParameters(); } @@ -155,7 +299,7 @@ public class CustomNamedCurves */ public static ASN1ObjectIdentifier getOID(String name) { - return (ASN1ObjectIdentifier)objIds.get(Strings.toLowerCase(name)); + return (ASN1ObjectIdentifier)nameToOID.get(Strings.toLowerCase(name)); } /** @@ -163,7 +307,7 @@ public class CustomNamedCurves */ public static String getName(ASN1ObjectIdentifier oid) { - return (String)names.get(oid); + return (String)oidToName.get(oid); } /** @@ -171,6 +315,6 @@ public class CustomNamedCurves */ public static Enumeration getNames() { - return objIds.keys(); + return nameToCurve.keys(); } } diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/ECElGamalEncryptor.java b/core/src/main/java/org/bouncycastle/crypto/ec/ECElGamalEncryptor.java index a5296830..48fc0467 100644 --- a/core/src/main/java/org/bouncycastle/crypto/ec/ECElGamalEncryptor.java +++ b/core/src/main/java/org/bouncycastle/crypto/ec/ECElGamalEncryptor.java @@ -67,7 +67,7 @@ public class ECElGamalEncryptor ECDomainParameters ec = key.getParameters(); BigInteger k = ECUtil.generateK(ec.getN(), random); - ECMultiplier basePointMultiplier = new FixedPointCombMultiplier(); + ECMultiplier basePointMultiplier = createBasePointMultiplier(); ECPoint[] gamma_phi = new ECPoint[]{ basePointMultiplier.multiply(ec.getG(), k), @@ -78,4 +78,9 @@ public class ECElGamalEncryptor return new ECPair(gamma_phi[0], gamma_phi[1]); } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/ECFixedTransform.java b/core/src/main/java/org/bouncycastle/crypto/ec/ECFixedTransform.java index 02f5ca37..2c6a920b 100644 --- a/core/src/main/java/org/bouncycastle/crypto/ec/ECFixedTransform.java +++ b/core/src/main/java/org/bouncycastle/crypto/ec/ECFixedTransform.java @@ -58,7 +58,7 @@ public class ECFixedTransform ECDomainParameters ec = key.getParameters(); BigInteger n = ec.getN(); - ECMultiplier basePointMultiplier = new FixedPointCombMultiplier(); + ECMultiplier basePointMultiplier = createBasePointMultiplier(); BigInteger k = this.k.mod(n); ECPoint[] gamma_phi = new ECPoint[]{ @@ -80,4 +80,9 @@ public class ECFixedTransform { return k; } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/ECNewPublicKeyTransform.java b/core/src/main/java/org/bouncycastle/crypto/ec/ECNewPublicKeyTransform.java index 9f7a0bf1..112d20c1 100644 --- a/core/src/main/java/org/bouncycastle/crypto/ec/ECNewPublicKeyTransform.java +++ b/core/src/main/java/org/bouncycastle/crypto/ec/ECNewPublicKeyTransform.java @@ -68,7 +68,7 @@ public class ECNewPublicKeyTransform ECDomainParameters ec = key.getParameters(); BigInteger n = ec.getN(); - ECMultiplier basePointMultiplier = new FixedPointCombMultiplier(); + ECMultiplier basePointMultiplier = createBasePointMultiplier(); BigInteger k = ECUtil.generateK(n, random); ECPoint[] gamma_phi = new ECPoint[]{ @@ -80,4 +80,9 @@ public class ECNewPublicKeyTransform return new ECPair(gamma_phi[0], gamma_phi[1]); } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/ECNewRandomnessTransform.java b/core/src/main/java/org/bouncycastle/crypto/ec/ECNewRandomnessTransform.java index c146a0fb..7bfc0b30 100644 --- a/core/src/main/java/org/bouncycastle/crypto/ec/ECNewRandomnessTransform.java +++ b/core/src/main/java/org/bouncycastle/crypto/ec/ECNewRandomnessTransform.java @@ -73,7 +73,7 @@ public class ECNewRandomnessTransform ECDomainParameters ec = key.getParameters(); BigInteger n = ec.getN(); - ECMultiplier basePointMultiplier = new FixedPointCombMultiplier(); + ECMultiplier basePointMultiplier = createBasePointMultiplier(); BigInteger k = ECUtil.generateK(n, random); ECPoint[] gamma_phi = new ECPoint[]{ @@ -97,4 +97,9 @@ public class ECNewRandomnessTransform { return lastK; } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java index fdf3f6d3..08cf738e 100644 --- a/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java +++ b/core/src/main/java/org/bouncycastle/crypto/engines/IDEAEngine.java @@ -10,22 +10,12 @@ import org.bouncycastle.crypto.params.KeyParameter; * A class that provides a basic International Data Encryption Algorithm (IDEA) engine. * <p> * This implementation is based on the "HOWTO: INTERNATIONAL DATA ENCRYPTION ALGORITHM" - * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (baring 1 typo at the + * implementation summary by Fauzan Mirza (F.U.Mirza@sheffield.ac.uk). (barring 1 typo at the * end of the mulinv function!). * <p> * It can be found at ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/idea/ * <p> - * Note 1: This algorithm is patented in the USA, Japan, and Europe including - * at least Austria, France, Germany, Italy, Netherlands, Spain, Sweden, Switzerland - * and the United Kingdom. Non-commercial use is free, however any commercial - * products are liable for royalties. Please see - * <a href="http://www.mediacrypt.com">www.mediacrypt.com</a> for - * further details. This announcement has been included at the request of - * the patent holders. - * <p> - * Note 2: Due to the requests concerning the above, this algorithm is now only - * included in the extended Bouncy Castle provider and JCE signed jars. It is - * not included in the default distributions. + * Note: This algorithm was patented in the USA, Japan and Europe. These patents expired in 2011/2012. */ public class IDEAEngine implements BlockCipher diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java b/core/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java index e0d86fc3..d395d5d3 100644 --- a/core/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java +++ b/core/src/main/java/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java @@ -19,7 +19,6 @@ class DHKeyGeneratorHelper BigInteger calculatePrivate(DHParameters dhParams, SecureRandom random) { - BigInteger p = dhParams.getP(); int limit = dhParams.getL(); if (limit != 0) @@ -34,12 +33,12 @@ class DHKeyGeneratorHelper min = ONE.shiftLeft(m - 1); } - BigInteger max = p.subtract(TWO); BigInteger q = dhParams.getQ(); - if (q != null) + if (q == null) { - max = q.subtract(TWO); + q = dhParams.getP(); } + BigInteger max = q.subtract(TWO); return BigIntegers.createRandomInRange(min, max, random); } diff --git a/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java index 38807a4c..1bae4638 100644 --- a/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java +++ b/core/src/main/java/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java @@ -11,6 +11,7 @@ import org.bouncycastle.crypto.params.ECKeyGenerationParameters; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECMultiplier; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.FixedPointCombMultiplier; @@ -50,10 +51,15 @@ public class ECKeyPairGenerator } while (d.equals(ZERO) || (d.compareTo(n) >= 0)); - ECPoint Q = new FixedPointCombMultiplier().multiply(params.getG(), d); + ECPoint Q = createBasePointMultiplier().multiply(params.getG(), d); return new AsymmetricCipherKeyPair( new ECPublicKeyParameters(Q, params), new ECPrivateKeyParameters(d, params)); } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java new file mode 100644 index 00000000..beeb60bc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherIOException.java @@ -0,0 +1,26 @@ +package org.bouncycastle.crypto.io; + +import java.io.IOException; + +/** + * {@link IOException} wrapper around an exception indicating a problem with the use of a cipher. + */ +public class CipherIOException + extends IOException +{ + private static final long serialVersionUID = 1L; + + private final Throwable cause; + + public CipherIOException(String message, Throwable cause) + { + super(message); + + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } +}
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java index 38ebcb0c..11cd903b 100644 --- a/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java +++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherInputStream.java @@ -162,7 +162,7 @@ public class CipherInputStream /** * Reads data from the underlying stream and processes it with the cipher until the cipher * outputs data, and returns the next available byte. - * <p> + * <p/> * If the underlying stream is exhausted by this call, the cipher will be finalised. * * @throws IOException if there was an error closing the input stream. @@ -186,7 +186,7 @@ public class CipherInputStream /** * Reads data from the underlying stream and processes it with the cipher until the cipher * outputs data, and then returns up to <code>b.length</code> bytes in the provided array. - * <p> + * <p/> * If the underlying stream is exhausted by this call, the cipher will be finalised. * * @param b the buffer into which the data is read. @@ -206,7 +206,7 @@ public class CipherInputStream /** * Reads data from the underlying stream and processes it with the cipher until the cipher * outputs data, and then returns up to <code>len</code> bytes in the provided array. - * <p> + * <p/> * If the underlying stream is exhausted by this call, the cipher will be finalised. * * @param b the buffer into which the data is read. diff --git a/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java b/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java index 4b68adfd..17e7f362 100644 --- a/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java +++ b/core/src/main/java/org/bouncycastle/crypto/io/CipherOutputStream.java @@ -118,7 +118,7 @@ public class CipherOutputStream int len) throws IOException { - ensureCapacity(len); + ensureCapacity(len, false); if (bufferedBlockCipher != null) { @@ -149,24 +149,35 @@ public class CipherOutputStream /** * Ensure the ciphertext buffer has space sufficient to accept an upcoming output. * - * @param outputSize the size of the pending update. + * @param updateSize the size of the pending update. + * @param <code>true</code> iff this the cipher is to be finalised. */ - private void ensureCapacity(int outputSize) + private void ensureCapacity(int updateSize, boolean finalOutput) { - // This overestimates buffer on updates for AEAD/padded, but keeps it simple. - int bufLen; - if (bufferedBlockCipher != null) + int bufLen = updateSize; + if (finalOutput) { - bufLen = bufferedBlockCipher.getOutputSize(outputSize); - } - else if (aeadBlockCipher != null) - { - bufLen = aeadBlockCipher.getOutputSize(outputSize); + if (bufferedBlockCipher != null) + { + bufLen = bufferedBlockCipher.getOutputSize(updateSize); + } + else if (aeadBlockCipher != null) + { + bufLen = aeadBlockCipher.getOutputSize(updateSize); + } } else { - bufLen = outputSize; + if (bufferedBlockCipher != null) + { + bufLen = bufferedBlockCipher.getUpdateOutputSize(updateSize); + } + else if (aeadBlockCipher != null) + { + bufLen = aeadBlockCipher.getUpdateOutputSize(updateSize); + } } + if ((buf == null) || (buf.length < bufLen)) { buf = new byte[bufLen]; @@ -212,7 +223,7 @@ public class CipherOutputStream public void close() throws IOException { - ensureCapacity(0); + ensureCapacity(0, true); IOException error = null; try { @@ -241,7 +252,7 @@ public class CipherOutputStream } catch (Exception e) { - error = new IOException("Error closing stream: " + e); + error = new CipherIOException("Error closing stream: ", e); } try diff --git a/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java b/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java index b601d4c1..46561c67 100644 --- a/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java +++ b/core/src/main/java/org/bouncycastle/crypto/io/InvalidCipherTextIOException.java @@ -8,21 +8,12 @@ import java.io.IOException; * expose invalid ciphertext errors. */ public class InvalidCipherTextIOException - extends IOException + extends CipherIOException { private static final long serialVersionUID = 1L; - private final Throwable cause; - public InvalidCipherTextIOException(String message, Throwable cause) { - super(message); - - this.cause = cause; - } - - public Throwable getCause() - { - return cause; + super(message, cause); } }
\ No newline at end of file diff --git a/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java b/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java index 746d26ca..517acfb1 100755 --- a/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java +++ b/core/src/main/java/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java @@ -123,7 +123,7 @@ public class ECIESKeyEncapsulation // Compute the static-ephemeral key agreement BigInteger rPrime = CofactorMode ? r.multiply(h).mod(n) : r; - ECMultiplier basePointMultiplier = new FixedPointCombMultiplier(); + ECMultiplier basePointMultiplier = createBasePointMultiplier(); ECPoint[] ghTilde = new ECPoint[]{ basePointMultiplier.multiply(ecParams.getG(), r), @@ -236,4 +236,9 @@ public class ECIESKeyEncapsulation { return decrypt(in, 0, in.length, keyLen); } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/macs/SipHash.java b/core/src/main/java/org/bouncycastle/crypto/macs/SipHash.java index 5a4845ca..35079aba 100644 --- a/core/src/main/java/org/bouncycastle/crypto/macs/SipHash.java +++ b/core/src/main/java/org/bouncycastle/crypto/macs/SipHash.java @@ -5,7 +5,6 @@ import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.Mac; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.util.Pack; -import org.bouncycastle.util.Arrays; /** * Implementation of SipHash as specified in "SipHash: a fast short-input PRF", by Jean-Philippe @@ -19,14 +18,13 @@ import org.bouncycastle.util.Arrays; public class SipHash implements Mac { - protected final int c, d; protected long k0, k1; - protected long v0, v1, v2, v3, v4; + protected long v0, v1, v2, v3; - protected byte[] buf = new byte[8]; - protected int bufPos = 0; + protected long m = 0; + protected int wordPos = 0; protected int wordCount = 0; /** @@ -34,7 +32,7 @@ public class SipHash */ public SipHash() { - // use of this confuses flow analyser on earlier JDKs. + // use of 'this' confuses the flow analyser on earlier JDKs. this.c = 2; this.d = 4; } @@ -84,12 +82,13 @@ public class SipHash public void update(byte input) throws IllegalStateException { + m >>>= 8; + m |= (input & 0xffL) << 56; - buf[bufPos] = input; - if (++bufPos == buf.length) + if (++wordPos == 8) { processMessageWord(); - bufPos = 0; + wordPos = 0; } } @@ -97,14 +96,41 @@ public class SipHash throws DataLengthException, IllegalStateException { - - for (int i = 0; i < length; ++i) + int i = 0, fullWords = length & ~7; + if (wordPos == 0) { - buf[bufPos] = input[offset + i]; - if (++bufPos == buf.length) + for (; i < fullWords; i += 8) { + m = Pack.littleEndianToLong(input, offset + i); processMessageWord(); - bufPos = 0; + } + for (; i < length; ++i) + { + m >>>= 8; + m |= (input[offset + i] & 0xffL) << 56; + } + wordPos = length - fullWords; + } + else + { + int bits = wordPos << 3; + for (; i < fullWords; i += 8) + { + long n = Pack.littleEndianToLong(input, offset + i); + m = (n << bits) | (m >>> -bits); + processMessageWord(); + m = n; + } + for (; i < length; ++i) + { + m >>>= 8; + m |= (input[offset + i] & 0xffL) << 56; + + if (++wordPos == 8) + { + processMessageWord(); + wordPos = 0; + } } } } @@ -112,12 +138,10 @@ public class SipHash public long doFinal() throws DataLengthException, IllegalStateException { - - buf[7] = (byte)(((wordCount << 3) + bufPos) & 0xff); - while (bufPos < 7) - { - buf[bufPos++] = 0; - } + // NOTE: 2 distinct shifts to avoid "64-bit shift" when wordPos == 0 + m >>>= ((7 - wordPos) << 3); + m >>>= 8; + m |= (((wordCount << 3) + wordPos) & 0xffL) << 56; processMessageWord(); @@ -135,7 +159,6 @@ public class SipHash public int doFinal(byte[] out, int outOff) throws DataLengthException, IllegalStateException { - long result = doFinal(); Pack.longToLittleEndian(result, out, outOff); return 8; @@ -143,22 +166,19 @@ public class SipHash public void reset() { - v0 = k0 ^ 0x736f6d6570736575L; v1 = k1 ^ 0x646f72616e646f6dL; v2 = k0 ^ 0x6c7967656e657261L; v3 = k1 ^ 0x7465646279746573L; - Arrays.fill(buf, (byte)0); - bufPos = 0; + m = 0; + wordPos = 0; wordCount = 0; } protected void processMessageWord() { - ++wordCount; - long m = Pack.littleEndianToLong(buf, 0); v3 ^= m; applySipRounds(c); v0 ^= m; @@ -166,27 +186,31 @@ public class SipHash protected void applySipRounds(int n) { + long r0 = v0, r1 = v1, r2 = v2, r3 = v3; + for (int r = 0; r < n; ++r) { - v0 += v1; - v2 += v3; - v1 = rotateLeft(v1, 13); - v3 = rotateLeft(v3, 16); - v1 ^= v0; - v3 ^= v2; - v0 = rotateLeft(v0, 32); - v2 += v1; - v0 += v3; - v1 = rotateLeft(v1, 17); - v3 = rotateLeft(v3, 21); - v1 ^= v2; - v3 ^= v0; - v2 = rotateLeft(v2, 32); + r0 += r1; + r2 += r3; + r1 = rotateLeft(r1, 13); + r3 = rotateLeft(r3, 16); + r1 ^= r0; + r3 ^= r2; + r0 = rotateLeft(r0, 32); + r2 += r1; + r0 += r3; + r1 = rotateLeft(r1, 17); + r3 = rotateLeft(r3, 21); + r1 ^= r2; + r3 ^= r0; + r2 = rotateLeft(r2, 32); } + + v0 = r0; v1 = r1; v2 = r2; v3 = r3; } protected static long rotateLeft(long x, int n) { - return (x << n) | (x >>> (64 - n)); + return (x << n) | (x >>> -n); } } diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java index 71b75954..3a2f73a3 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/AEADBlockCipher.java @@ -7,6 +7,15 @@ import org.bouncycastle.crypto.InvalidCipherTextException; /** * A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data. + * <p/> + * Implementations of this interface may operate in a packet mode (where all input data is buffered and + * processed dugin the call to {@link #doFinal(byte[], int)}), or in a streaming mode (where output data is + * incrementally produced with each call to {@link #processByte(byte, byte[], int)} or + * {@link #processBytes(byte[], int, int, byte[], int)}. + * <br/>This is important to consider during decryption: in a streaming mode, unauthenticated plaintext data + * may be output prior to the call to {@link #doFinal(byte[], int)} that results in an authentication + * failure. The higher level protocol utilising this cipher must ensure the plaintext data is handled + * appropriately until the end of data is reached and the entire ciphertext is authenticated. * @see org.bouncycastle.crypto.params.AEADParameters */ public interface AEADBlockCipher @@ -101,7 +110,11 @@ public interface AEADBlockCipher /** * return the size of the output buffer required for a processBytes * an input of len bytes. - * + * <p/> + * The returned size may be dependent on the initialisation of this cipher + * and may not be accurate once subsequent input data is processed - this method + * should be invoked immediately prior to input data being processed. + * * @param len the length of the input. * @return the space required to accommodate a call to processBytes * with len bytes of input. @@ -111,7 +124,12 @@ public interface AEADBlockCipher /** * return the size of the output buffer required for a processBytes plus a * doFinal with an input of len bytes. - * + * <p/> + * The returned size may be dependent on the initialisation of this cipher + * and may not be accurate once subsequent input data is processed - this method + * should be invoked immediately prior to a call to final processing of input data + * and a call to {@link #doFinal(byte[], int)}. + * * @param len the length of the input. * @return the space required to accommodate a call to processBytes and doFinal * with len bytes of input. diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java index fef51fdb..7f870ca2 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/CCMBlockCipher.java @@ -7,6 +7,7 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.macs.CBCBlockCipherMac; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.ParametersWithIV; @@ -42,7 +43,7 @@ public class CCMBlockCipher this.cipher = c; this.blockSize = c.getBlockSize(); this.macBlock = new byte[blockSize]; - + if (blockSize != 16) { throw new IllegalArgumentException("cipher required with a block size of 16."); @@ -99,7 +100,7 @@ public class CCMBlockCipher { throw new IllegalArgumentException("nonce must have length from 7 to 13 octets"); } - + reset(); } @@ -130,6 +131,10 @@ public class CCMBlockCipher public int processBytes(byte[] in, int inOff, int inLen, byte[] out, int outOff) throws DataLengthException, IllegalStateException { + if (in.length < (inOff + inLen)) + { + throw new DataLengthException("Input buffer too short"); + } data.write(in, inOff, inLen); return 0; @@ -155,15 +160,15 @@ public class CCMBlockCipher /** * Returns a byte array containing the mac calculated as part of the * last encrypt or decrypt operation. - * + * * @return the last mac calculated. */ public byte[] getMac() { byte[] mac = new byte[macSize]; - + System.arraycopy(macBlock, 0, mac, 0, mac.length); - + return mac; } @@ -267,7 +272,7 @@ public class CCMBlockCipher outputLen = inLen + macSize; if (output.length < (outputLen + outOff)) { - throw new DataLengthException("Output buffer too short."); + throw new OutputLengthException("Output buffer too short."); } calculateMac(in, inOff, inLen, macBlock); @@ -300,7 +305,7 @@ public class CCMBlockCipher outputLen = inLen - macSize; if (output.length < (outputLen + outOff)) { - throw new DataLengthException("Output buffer too short."); + throw new OutputLengthException("Output buffer too short."); } System.arraycopy(in, inOff + outputLen, macBlock, 0, macSize); @@ -350,18 +355,18 @@ public class CCMBlockCipher // build b0 // byte[] b0 = new byte[16]; - + if (hasAssociatedText()) { b0[0] |= 0x40; } - + b0[0] |= (((cMac.getMacSize() - 2) / 2) & 0x7) << 3; b0[0] |= ((15 - nonce.length) - 1) & 0x7; - + System.arraycopy(nonce, 0, b0, 1, nonce.length); - + int q = dataLen; int count = 1; while (q > 0) @@ -370,22 +375,22 @@ public class CCMBlockCipher q >>>= 8; count++; } - + cMac.update(b0, 0, b0.length); - + // // process associated text // if (hasAssociatedText()) { int extra; - + int textLength = getAssociatedTextLength(); if (textLength < ((1 << 16) - (1 << 8))) { cMac.update((byte)(textLength >> 8)); cMac.update((byte)textLength); - + extra = 2; } else // can't go any higher than 2^32 @@ -396,7 +401,7 @@ public class CCMBlockCipher cMac.update((byte)(textLength >> 16)); cMac.update((byte)(textLength >> 8)); cMac.update((byte)textLength); - + extra = 6; } @@ -418,7 +423,7 @@ public class CCMBlockCipher } } } - + // // add the text // diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java index 8f740006..209d5cdb 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/EAXBlockCipher.java @@ -5,22 +5,23 @@ import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.Mac; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.macs.CMac; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.ParametersWithIV; import org.bouncycastle.util.Arrays; /** - * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and + * A Two-Pass Authenticated-Encryption Scheme Optimized for Simplicity and * Efficiency - by M. Bellare, P. Rogaway, D. Wagner. - * + * * http://www.cs.ucdavis.edu/~rogaway/papers/eax.pdf - * - * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block - * cipher to encrypt and authenticate data. It's on-line (the length of a + * + * EAX is an AEAD scheme based on CTR and OMAC1/CMAC, that uses a single block + * cipher to encrypt and authenticate data. It's on-line (the length of a * message isn't needed to begin processing it), has good performances, it's * simple and provably secure (provided the underlying block cipher is secure). - * + * * Of course, this implementations is NOT thread-safe. */ public class EAXBlockCipher @@ -43,7 +44,7 @@ public class EAXBlockCipher private byte[] nonceMac; private byte[] associatedTextMac; private byte[] macBlock; - + private int macSize; private byte[] bufBlock; private int bufOff; @@ -61,7 +62,6 @@ public class EAXBlockCipher blockSize = cipher.getBlockSize(); mac = new CMac(cipher); macBlock = new byte[blockSize]; - bufBlock = new byte[blockSize * 2]; associatedTextMac = new byte[mac.getMacSize()]; nonceMac = new byte[mac.getMacSize()]; this.cipher = new SICBlockCipher(cipher); @@ -113,6 +113,8 @@ public class EAXBlockCipher throw new IllegalArgumentException("invalid parameters passed to EAX"); } + bufBlock = new byte[forEncryption ? blockSize : (blockSize + macSize)]; + byte[] tag = new byte[blockSize]; // Key reuse implemented in CBC mode of underlying CMac @@ -123,9 +125,9 @@ public class EAXBlockCipher mac.update(nonce, 0, nonce.length); mac.doFinal(nonceMac, 0); - // Same BlockCipher underlies this and the mac, so reuse last key on cipher + // Same BlockCipher underlies this and the mac, so reuse last key on cipher cipher.init(true, new ParametersWithIV(null, nonceMac)); - + reset(); } @@ -218,6 +220,11 @@ public class EAXBlockCipher { initCipher(); + if (in.length < (inOff + len)) + { + throw new DataLengthException("Input buffer too short"); + } + int resultLen = 0; for (int i = 0; i != len; i++) @@ -240,12 +247,11 @@ public class EAXBlockCipher if (forEncryption) { - if (out.length < (outOff + extra)) + if (out.length < (outOff + extra + macSize)) { - throw new DataLengthException("Output buffer too short"); + throw new OutputLengthException("Output buffer too short"); } cipher.processBlock(bufBlock, 0, tmp, 0); - cipher.processBlock(bufBlock, blockSize, tmp, blockSize); System.arraycopy(tmp, 0, out, outOff, extra); @@ -261,6 +267,10 @@ public class EAXBlockCipher } else { + if (out.length < (outOff + extra - macSize)) + { + throw new OutputLengthException("Output buffer too short"); + } if (extra < macSize) { throw new InvalidCipherTextException("data too short"); @@ -270,7 +280,6 @@ public class EAXBlockCipher mac.update(bufBlock, 0, extra - macSize); cipher.processBlock(bufBlock, 0, tmp, 0); - cipher.processBlock(bufBlock, blockSize, tmp, blockSize); System.arraycopy(tmp, 0, out, outOff, extra - macSize); } @@ -329,6 +338,10 @@ public class EAXBlockCipher if (bufOff == bufBlock.length) { + if (out.length < (outOff + blockSize)) + { + throw new OutputLengthException("Output buffer is too short"); + } // TODO Could move the processByte(s) calls to here // initCipher(); @@ -347,8 +360,12 @@ public class EAXBlockCipher size = cipher.processBlock(bufBlock, 0, out, outOff); } - bufOff = blockSize; - System.arraycopy(bufBlock, blockSize, bufBlock, 0, blockSize); + bufOff = 0; + if (!forEncryption) + { + System.arraycopy(bufBlock, blockSize, bufBlock, 0, macSize); + bufOff = macSize; + } return size; } diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java index 9e617ec9..59c2eb36 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/GCMBlockCipher.java @@ -4,6 +4,7 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.modes.gcm.GCMExponentiator; import org.bouncycastle.crypto.modes.gcm.GCMMultiplier; import org.bouncycastle.crypto.modes.gcm.Tables1kGCMExponentiator; @@ -23,7 +24,7 @@ public class GCMBlockCipher { private static final int BLOCK_SIZE = 16; - // not final due to a compiler bug + // not final due to a compiler bug private BlockCipher cipher; private GCMMultiplier multiplier; private GCMExponentiator exp; @@ -102,7 +103,7 @@ public class GCMBlockCipher throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits); } - macSize = macSizeBits / 8; + macSize = macSizeBits / 8; keyParam = param.getKey(); } else if (params instanceof ParametersWithIV) @@ -119,7 +120,7 @@ public class GCMBlockCipher throw new IllegalArgumentException("invalid parameters passed to GCM"); } - int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize); + int bufLength = forEncryption ? BLOCK_SIZE : (BLOCK_SIZE + macSize); this.bufBlock = new byte[bufLength]; if (nonce == null || nonce.length < 1) @@ -271,6 +272,10 @@ public class GCMBlockCipher public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException { + if (in.length < (inOff + len)) + { + throw new DataLengthException("Input buffer too short"); + } int resultLen = 0; for (int i = 0; i < len; ++i) @@ -288,6 +293,10 @@ public class GCMBlockCipher private void outputBlock(byte[] output, int offset) { + if (output.length < (offset + BLOCK_SIZE)) + { + throw new OutputLengthException("Output buffer too short"); + } if (totalLength == 0) { initCipher(); @@ -324,6 +333,10 @@ public class GCMBlockCipher if (extra > 0) { + if (out.length < (outOff + extra)) + { + throw new OutputLengthException("Output buffer too short"); + } gCTRPartial(bufBlock, 0, extra, out, outOff); } @@ -390,6 +403,10 @@ public class GCMBlockCipher if (forEncryption) { + if (out.length < (outOff + extra + macSize)) + { + throw new OutputLengthException("Output buffer too short"); + } // Append T to the message System.arraycopy(macBlock, 0, out, outOff + bufOff, macSize); resultLen += macSize; diff --git a/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java index c3e8a96c..b942fbfb 100644 --- a/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/modes/OCBBlockCipher.java @@ -6,6 +6,7 @@ import org.bouncycastle.crypto.BlockCipher; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DataLengthException; import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.OutputLengthException; import org.bouncycastle.crypto.params.AEADParameters; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.crypto.params.ParametersWithIV; @@ -317,6 +318,10 @@ public class OCBBlockCipher public int processBytes(byte[] input, int inOff, int len, byte[] output, int outOff) throws DataLengthException { + if (input.length < (inOff + len)) + { + throw new DataLengthException("Input buffer too short"); + } int resultLen = 0; for (int i = 0; i < len; ++i) @@ -378,6 +383,10 @@ public class OCBBlockCipher xor(mainBlock, Pad); + if (output.length < (outOff + mainBlockPos)) + { + throw new OutputLengthException("Output buffer too short"); + } System.arraycopy(mainBlock, 0, output, outOff, mainBlockPos); if (!forEncryption) @@ -405,6 +414,10 @@ public class OCBBlockCipher if (forEncryption) { + if (output.length < (outOff + resultLen + macSize)) + { + throw new OutputLengthException("Output buffer too short"); + } // Append tag to the message System.arraycopy(macBlock, 0, output, outOff + resultLen, macSize); resultLen += macSize; @@ -456,6 +469,11 @@ public class OCBBlockCipher protected void processMainBlock(byte[] output, int outOff) { + if (output.length < (outOff + BLOCK_SIZE)) + { + throw new OutputLengthException("Output buffer too short"); + } + /* * OCB-ENCRYPT/OCB-DECRYPT: Process any whole blocks */ diff --git a/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java b/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java index ee3fd60e..d5928f70 100644 --- a/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java +++ b/core/src/main/java/org/bouncycastle/crypto/paddings/PaddedBufferedBlockCipher.java @@ -125,7 +125,7 @@ public class PaddedBufferedBlockCipher if (leftOver == 0) { - return total - buf.length; + return Math.max(0, total - buf.length); } return total - leftOver; diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java index 84fe4a40..5ab8f469 100644 --- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java +++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java @@ -310,6 +310,16 @@ public class CTRSP800DRBG } /** + * Return the block size (in bits) of the DRBG. + * + * @return the number of bits produced on each internal round of the DRBG. + */ + public int getBlockSize() + { + return _V.length * 8; + } + + /** * Populate a passed in array with random data. * * @param output output array for generated bits. diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java index a5607d5a..4e1b881d 100644 --- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java +++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/DualECSP800DRBG.java @@ -149,6 +149,16 @@ public class DualECSP800DRBG } /** + * Return the block size (in bits) of the DRBG. + * + * @return the number of bits produced on each internal round of the DRBG. + */ + public int getBlockSize() + { + return _outlen * 8; + } + + /** * Populate a passed in array with random data. * * @param output output array for generated bits. diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java index 3ddeaac6..f4ef2c45 100644 --- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java +++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HMacSP800DRBG.java @@ -88,6 +88,16 @@ public class HMacSP800DRBG } /** + * Return the block size (in bits) of the DRBG. + * + * @return the number of bits produced on each round of the DRBG. + */ + public int getBlockSize() + { + return _V.length * 8; + } + + /** * Populate a passed in array with random data. * * @param output output array for generated bits. diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java index 4ed57163..d6ab4f53 100644 --- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java +++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/HashSP800DRBG.java @@ -88,6 +88,16 @@ public class HashSP800DRBG } /** + * Return the block size (in bits) of the DRBG. + * + * @return the number of bits produced on each internal round of the DRBG. + */ + public int getBlockSize() + { + return _digest.getDigestSize() * 8; + } + + /** * Populate a passed in array with random data. * * @param output output array for generated bits. @@ -226,12 +236,17 @@ public class HashSP800DRBG private byte[] hash(byte[] input) { - _digest.update(input, 0, input.length); byte[] hash = new byte[_digest.getDigestSize()]; - _digest.doFinal(hash, 0); + doHash(input, hash); return hash; } - + + private void doHash(byte[] input, byte[] output) + { + _digest.update(input, 0, input.length); + _digest.doFinal(output, 0); + } + // 1. m = [requested_number_of_bits / outlen] // 2. data = V. // 3. W = the Null string. @@ -251,10 +266,10 @@ public class HashSP800DRBG byte[] W = new byte[lengthInBits / 8]; - byte[] dig; + byte[] dig = new byte[_digest.getDigestSize()]; for (int i = 0; i <= m; i++) { - dig = hash(data); + doHash(data, dig); int bytesToCopy = ((W.length - i * dig.length) > dig.length) ? dig.length diff --git a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java index 93bc8945..7a919f31 100644 --- a/core/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java +++ b/core/src/main/java/org/bouncycastle/crypto/prng/drbg/SP80090DRBG.java @@ -6,6 +6,13 @@ package org.bouncycastle.crypto.prng.drbg; public interface SP80090DRBG { /** + * Return the block size of the DRBG. + * + * @return the block size (in bits) produced by each round of the DRBG. + */ + int getBlockSize(); + + /** * Populate a passed in array with random data. * * @param output output array for generated bits. diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/DSADigestSigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/DSADigestSigner.java index 2e4c48d3..684eb9c0 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/DSADigestSigner.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/DSADigestSigner.java @@ -5,9 +5,9 @@ import java.math.BigInteger; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Encoding; +import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; -import org.bouncycastle.asn1.DERInteger; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.DSA; @@ -142,8 +142,8 @@ public class DSADigestSigner throws IOException { ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new DERInteger(r)); - v.add(new DERInteger(s)); + v.add(new ASN1Integer(r)); + v.add(new ASN1Integer(s)); return new DERSequence(v).getEncoded(ASN1Encoding.DER); } @@ -156,8 +156,8 @@ public class DSADigestSigner return new BigInteger[] { - ((DERInteger)s.getObjectAt(0)).getValue(), - ((DERInteger)s.getObjectAt(1)).getValue() + ((ASN1Integer)s.getObjectAt(0)).getValue(), + ((ASN1Integer)s.getObjectAt(1)).getValue() }; } } diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java b/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java index 0a3ef37f..d0b893a6 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/DSTU4145Signer.java @@ -75,7 +75,7 @@ public class DSTU4145Signer BigInteger d = ((ECPrivateKeyParameters)key).getD(); - ECMultiplier basePointMultiplier = new FixedPointCombMultiplier(); + ECMultiplier basePointMultiplier = createBasePointMultiplier(); do { @@ -135,6 +135,11 @@ public class DSTU4145Signer return fieldElement2Integer(n, y).compareTo(r) == 0; } + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } + /** * Generates random integer such, than its bit length is less than that of n */ diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java index 26fd588e..8ea2a5b9 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECDSASigner.java @@ -97,7 +97,7 @@ public class ECDSASigner BigInteger r, s; - ECMultiplier basePointMultiplier = new FixedPointCombMultiplier(); + ECMultiplier basePointMultiplier = createBasePointMultiplier(); // 5.3.2 do // generate s @@ -169,7 +169,7 @@ public class ECDSASigner return v.equals(r); } - private BigInteger calculateE(BigInteger n, byte[] message) + protected BigInteger calculateE(BigInteger n, byte[] message) { int log2n = n.bitLength(); int messageBitLength = message.length * 8; @@ -181,4 +181,9 @@ public class ECDSASigner } return e; } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } } diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java index 47dc6bd9..0ef88762 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECGOST3410Signer.java @@ -1,155 +1,160 @@ -package org.bouncycastle.crypto.signers;
-
-import org.bouncycastle.crypto.CipherParameters;
-import org.bouncycastle.crypto.DSA;
-import org.bouncycastle.crypto.params.ECDomainParameters;
-import org.bouncycastle.crypto.params.ECKeyParameters;
-import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
-import org.bouncycastle.crypto.params.ECPublicKeyParameters;
-import org.bouncycastle.crypto.params.ParametersWithRandom;
-import org.bouncycastle.math.ec.ECAlgorithms;
-import org.bouncycastle.math.ec.ECConstants;
-import org.bouncycastle.math.ec.ECMultiplier;
-import org.bouncycastle.math.ec.ECPoint;
-import org.bouncycastle.math.ec.FixedPointCombMultiplier;
-
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
-/**
- * GOST R 34.10-2001 Signature Algorithm
- */
-public class ECGOST3410Signer
- implements DSA
-{
- ECKeyParameters key;
-
- SecureRandom random;
-
- public void init(
- boolean forSigning,
- CipherParameters param)
- {
- if (forSigning)
- {
- if (param instanceof ParametersWithRandom)
- {
- ParametersWithRandom rParam = (ParametersWithRandom)param;
-
- this.random = rParam.getRandom();
- this.key = (ECPrivateKeyParameters)rParam.getParameters();
- }
- else
- {
- this.random = new SecureRandom();
- this.key = (ECPrivateKeyParameters)param;
- }
- }
- else
- {
- this.key = (ECPublicKeyParameters)param;
- }
- }
-
- /**
- * generate a signature for the given message using the key we were
- * initialised with. For conventional GOST3410 the message should be a GOST3411
- * hash of the message of interest.
- *
- * @param message the message that will be verified later.
- */
- public BigInteger[] generateSignature(
- byte[] message)
- {
- byte[] mRev = new byte[message.length]; // conversion is little-endian
- for (int i = 0; i != mRev.length; i++)
- {
- mRev[i] = message[mRev.length - 1 - i];
- }
-
- BigInteger e = new BigInteger(1, mRev);
-
- ECDomainParameters ec = key.getParameters();
- BigInteger n = ec.getN();
- BigInteger d = ((ECPrivateKeyParameters)key).getD();
-
- BigInteger r, s;
-
- ECMultiplier basePointMultiplier = new FixedPointCombMultiplier();
-
- do // generate s
- {
- BigInteger k;
- do // generate r
- {
- do
- {
- k = new BigInteger(n.bitLength(), random);
- }
- while (k.equals(ECConstants.ZERO));
-
- ECPoint p = basePointMultiplier.multiply(ec.getG(), k).normalize();
-
- r = p.getAffineXCoord().toBigInteger().mod(n);
- }
- while (r.equals(ECConstants.ZERO));
-
- s = (k.multiply(e)).add(d.multiply(r)).mod(n);
- }
- while (s.equals(ECConstants.ZERO));
-
- return new BigInteger[]{ r, s };
- }
-
- /**
- * return true if the value r and s represent a GOST3410 signature for
- * the passed in message (for standard GOST3410 the message should be
- * a GOST3411 hash of the real message to be verified).
- */
- public boolean verifySignature(
- byte[] message,
- BigInteger r,
- BigInteger s)
- {
- byte[] mRev = new byte[message.length]; // conversion is little-endian
- for (int i = 0; i != mRev.length; i++)
- {
- mRev[i] = message[mRev.length - 1 - i];
- }
-
- BigInteger e = new BigInteger(1, mRev);
- BigInteger n = key.getParameters().getN();
-
- // r in the range [1,n-1]
- if (r.compareTo(ECConstants.ONE) < 0 || r.compareTo(n) >= 0)
- {
- return false;
- }
-
- // s in the range [1,n-1]
- if (s.compareTo(ECConstants.ONE) < 0 || s.compareTo(n) >= 0)
- {
- return false;
- }
-
- BigInteger v = e.modInverse(n);
-
- BigInteger z1 = s.multiply(v).mod(n);
- BigInteger z2 = (n.subtract(r)).multiply(v).mod(n);
-
- ECPoint G = key.getParameters().getG(); // P
- ECPoint Q = ((ECPublicKeyParameters)key).getQ();
-
- ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, z1, Q, z2).normalize();
-
- // components must be bogus.
- if (point.isInfinity())
- {
- return false;
- }
-
- BigInteger R = point.getAffineXCoord().toBigInteger().mod(n);
-
- return R.equals(r);
- }
-}
+package org.bouncycastle.crypto.signers; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.DSA; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECKeyParameters; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.math.ec.ECAlgorithms; +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECMultiplier; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.FixedPointCombMultiplier; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * GOST R 34.10-2001 Signature Algorithm + */ +public class ECGOST3410Signer + implements DSA +{ + ECKeyParameters key; + + SecureRandom random; + + public void init( + boolean forSigning, + CipherParameters param) + { + if (forSigning) + { + if (param instanceof ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + + this.random = rParam.getRandom(); + this.key = (ECPrivateKeyParameters)rParam.getParameters(); + } + else + { + this.random = new SecureRandom(); + this.key = (ECPrivateKeyParameters)param; + } + } + else + { + this.key = (ECPublicKeyParameters)param; + } + } + + /** + * generate a signature for the given message using the key we were + * initialised with. For conventional GOST3410 the message should be a GOST3411 + * hash of the message of interest. + * + * @param message the message that will be verified later. + */ + public BigInteger[] generateSignature( + byte[] message) + { + byte[] mRev = new byte[message.length]; // conversion is little-endian + for (int i = 0; i != mRev.length; i++) + { + mRev[i] = message[mRev.length - 1 - i]; + } + + BigInteger e = new BigInteger(1, mRev); + + ECDomainParameters ec = key.getParameters(); + BigInteger n = ec.getN(); + BigInteger d = ((ECPrivateKeyParameters)key).getD(); + + BigInteger r, s; + + ECMultiplier basePointMultiplier = createBasePointMultiplier(); + + do // generate s + { + BigInteger k; + do // generate r + { + do + { + k = new BigInteger(n.bitLength(), random); + } + while (k.equals(ECConstants.ZERO)); + + ECPoint p = basePointMultiplier.multiply(ec.getG(), k).normalize(); + + r = p.getAffineXCoord().toBigInteger().mod(n); + } + while (r.equals(ECConstants.ZERO)); + + s = (k.multiply(e)).add(d.multiply(r)).mod(n); + } + while (s.equals(ECConstants.ZERO)); + + return new BigInteger[]{ r, s }; + } + + /** + * return true if the value r and s represent a GOST3410 signature for + * the passed in message (for standard GOST3410 the message should be + * a GOST3411 hash of the real message to be verified). + */ + public boolean verifySignature( + byte[] message, + BigInteger r, + BigInteger s) + { + byte[] mRev = new byte[message.length]; // conversion is little-endian + for (int i = 0; i != mRev.length; i++) + { + mRev[i] = message[mRev.length - 1 - i]; + } + + BigInteger e = new BigInteger(1, mRev); + BigInteger n = key.getParameters().getN(); + + // r in the range [1,n-1] + if (r.compareTo(ECConstants.ONE) < 0 || r.compareTo(n) >= 0) + { + return false; + } + + // s in the range [1,n-1] + if (s.compareTo(ECConstants.ONE) < 0 || s.compareTo(n) >= 0) + { + return false; + } + + BigInteger v = e.modInverse(n); + + BigInteger z1 = s.multiply(v).mod(n); + BigInteger z2 = (n.subtract(r)).multiply(v).mod(n); + + ECPoint G = key.getParameters().getG(); // P + ECPoint Q = ((ECPublicKeyParameters)key).getQ(); + + ECPoint point = ECAlgorithms.sumOfTwoMultiplies(G, z1, Q, z2).normalize(); + + // components must be bogus. + if (point.isInfinity()) + { + return false; + } + + BigInteger R = point.getAffineXCoord().toBigInteger().mod(n); + + return R.equals(r); + } + + protected ECMultiplier createBasePointMultiplier() + { + return new FixedPointCombMultiplier(); + } +} diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java index 72bbbcb4..3e839163 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/ECNRSigner.java @@ -101,7 +101,7 @@ public class ECNRSigner // BigInteger Vx = tempPair.getPublic().getW().getAffineX(); ECPublicKeyParameters V = (ECPublicKeyParameters)tempPair.getPublic(); // get temp's public key - BigInteger Vx = V.getQ().normalize().getAffineXCoord().toBigInteger(); // get the point's x coordinate + BigInteger Vx = V.getQ().getAffineXCoord().toBigInteger(); // get the point's x coordinate r = Vx.add(e).mod(n); } diff --git a/core/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java b/core/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java index aaae0645..f34b18c2 100644 --- a/core/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java +++ b/core/src/main/java/org/bouncycastle/crypto/signers/RSADigestSigner.java @@ -48,6 +48,8 @@ public class RSADigestSigner oidMap.put("SHA-256", NISTObjectIdentifiers.id_sha256); oidMap.put("SHA-384", NISTObjectIdentifiers.id_sha384); oidMap.put("SHA-512", NISTObjectIdentifiers.id_sha512); + oidMap.put("SHA-512/224", NISTObjectIdentifiers.id_sha512_224); + oidMap.put("SHA-512/256", NISTObjectIdentifiers.id_sha512_256); oidMap.put("MD2", PKCSObjectIdentifiers.md2); oidMap.put("MD4", PKCSObjectIdentifiers.md4); diff --git a/core/src/main/java/org/bouncycastle/crypto/util/Pack.java b/core/src/main/java/org/bouncycastle/crypto/util/Pack.java index f0da0bf0..e121e0f9 100644 --- a/core/src/main/java/org/bouncycastle/crypto/util/Pack.java +++ b/core/src/main/java/org/bouncycastle/crypto/util/Pack.java @@ -114,6 +114,15 @@ public abstract class Pack } } + public static void littleEndianToInt(byte[] bs, int bOff, int[] ns, int nOff, int count) + { + for (int i = 0; i < count; ++i) + { + ns[nOff + i] = littleEndianToInt(bs, bOff); + bOff += 4; + } + } + public static byte[] intToLittleEndian(int n) { byte[] bs = new byte[4]; diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java index 9e342ff9..92684ecc 100644 --- a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java +++ b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java @@ -9,7 +9,6 @@ import org.bouncycastle.asn1.ASN1InputStream; import org.bouncycastle.asn1.ASN1Integer; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1Primitive; -import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.oiw.ElGamalParameter; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import org.bouncycastle.asn1.pkcs.DHParameter; @@ -101,7 +100,7 @@ public class PrivateKeyFactory } else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm)) { - ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters()); + ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters()); ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters( diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java index b52d9bc0..cb130954 100644 --- a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java +++ b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java @@ -10,7 +10,6 @@ import org.bouncycastle.asn1.ASN1Integer; 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.oiw.ElGamalParameter; import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; @@ -136,7 +135,7 @@ public class PublicKeyFactory } else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm)) { - ElGamalParameter params = new ElGamalParameter((ASN1Sequence)algId.getParameters()); + ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters()); ASN1Integer derY = (ASN1Integer)keyInfo.parsePublicKey(); return new ElGamalPublicKeyParameters(derY.getValue(), new ElGamalParameters( diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java b/core/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java index 63ba1ac1..2d4a9708 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java +++ b/core/src/main/java/org/bouncycastle/math/ec/ECAlgorithms.java @@ -2,6 +2,8 @@ package org.bouncycastle.math.ec; import java.math.BigInteger; +import org.bouncycastle.math.ec.endo.ECEndomorphism; +import org.bouncycastle.math.ec.endo.GLVEndomorphism; import org.bouncycastle.math.field.FiniteField; import org.bouncycastle.math.field.PolynomialExtensionField; @@ -47,6 +49,12 @@ public class ECAlgorithms imported[i] = importPoint(c, ps[i]); } + ECEndomorphism endomorphism = c.getEndomorphism(); + if (endomorphism instanceof GLVEndomorphism) + { + return implSumOfMultipliesGLV(imported, ks, (GLVEndomorphism)endomorphism); + } + return implSumOfMultiplies(imported, ks); } @@ -66,6 +74,12 @@ public class ECAlgorithms } } + ECEndomorphism endomorphism = cp.getEndomorphism(); + if (endomorphism instanceof GLVEndomorphism) + { + return implSumOfMultipliesGLV(new ECPoint[]{ P, Q }, new BigInteger[]{ a, b }, (GLVEndomorphism)endomorphism); + } + return implShamirsTrickWNaf(P, a, Q, b); } @@ -178,23 +192,58 @@ public class ECAlgorithms static ECPoint implShamirsTrickWNaf(ECPoint P, BigInteger k, ECPoint Q, BigInteger l) { + boolean negK = k.signum() < 0, negL = l.signum() < 0; + + k = k.abs(); + l = l.abs(); + int widthP = Math.max(2, Math.min(16, WNafUtil.getWindowSize(k.bitLength()))); int widthQ = Math.max(2, Math.min(16, WNafUtil.getWindowSize(l.bitLength()))); WNafPreCompInfo infoP = WNafUtil.precompute(P, widthP, true); WNafPreCompInfo infoQ = WNafUtil.precompute(Q, widthQ, true); - ECPoint[] preCompP = infoP.getPreComp(); - ECPoint[] preCompQ = infoQ.getPreComp(); - ECPoint[] preCompNegP = infoP.getPreCompNeg(); - ECPoint[] preCompNegQ = infoQ.getPreCompNeg(); + ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp(); + ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp(); + ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg(); + ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg(); byte[] wnafP = WNafUtil.generateWindowNaf(widthP, k); byte[] wnafQ = WNafUtil.generateWindowNaf(widthQ, l); + return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ); + } + + static ECPoint implShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l) + { + boolean negK = k.signum() < 0, negL = l.signum() < 0; + + k = k.abs(); + l = l.abs(); + + int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(k.bitLength(), l.bitLength())))); + + ECPoint Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMapQ); + WNafPreCompInfo infoP = WNafUtil.getWNafPreCompInfo(P); + WNafPreCompInfo infoQ = WNafUtil.getWNafPreCompInfo(Q); + + ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp(); + ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp(); + ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg(); + ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg(); + + byte[] wnafP = WNafUtil.generateWindowNaf(width, k); + byte[] wnafQ = WNafUtil.generateWindowNaf(width, l); + + return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ); + } + + private static ECPoint implShamirsTrickWNaf(ECPoint[] preCompP, ECPoint[] preCompNegP, byte[] wnafP, + ECPoint[] preCompQ, ECPoint[] preCompNegQ, byte[] wnafQ) + { int len = Math.max(wnafP.length, wnafQ.length); - ECCurve curve = P.getCurve(); + ECCurve curve = preCompP[0].getCurve(); ECPoint infinity = curve.getInfinity(); ECPoint R = infinity; @@ -245,20 +294,90 @@ public class ECAlgorithms static ECPoint implSumOfMultiplies(ECPoint[] ps, BigInteger[] ks) { int count = ps.length; - int[] widths = new int[count]; + boolean[] negs = new boolean[count]; WNafPreCompInfo[] infos = new WNafPreCompInfo[count]; byte[][] wnafs = new byte[count][]; - int len = 0; for (int i = 0; i < count; ++i) { - widths[i] = Math.max(2, Math.min(16, WNafUtil.getWindowSize(ks[i].bitLength()))); - infos[i] = WNafUtil.precompute(ps[i], widths[i], true); - wnafs[i] = WNafUtil.generateWindowNaf(widths[i], ks[i]); + BigInteger ki = ks[i]; negs[i] = ki.signum() < 0; ki = ki.abs(); + + int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(ki.bitLength()))); + infos[i] = WNafUtil.precompute(ps[i], width, true); + wnafs[i] = WNafUtil.generateWindowNaf(width, ki); + } + + return implSumOfMultiplies(negs, infos, wnafs); + } + + static ECPoint implSumOfMultipliesGLV(ECPoint[] ps, BigInteger[] ks, GLVEndomorphism glvEndomorphism) + { + BigInteger n = ps[0].getCurve().getOrder(); + + int len = ps.length; + + BigInteger[] abs = new BigInteger[len << 1]; + for (int i = 0, j = 0; i < len; ++i) + { + BigInteger[] ab = glvEndomorphism.decomposeScalar(ks[i].mod(n)); + abs[j++] = ab[0]; + abs[j++] = ab[1]; + } + + ECPointMap pointMap = glvEndomorphism.getPointMap(); + if (glvEndomorphism.hasEfficientPointMap()) + { + return ECAlgorithms.implSumOfMultiplies(ps, pointMap, abs); + } + + ECPoint[] pqs = new ECPoint[len << 1]; + for (int i = 0, j = 0; i < len; ++i) + { + ECPoint p = ps[i], q = pointMap.map(p); + pqs[j++] = p; + pqs[j++] = q; + } + + return ECAlgorithms.implSumOfMultiplies(pqs, abs); + + } + + static ECPoint implSumOfMultiplies(ECPoint[] ps, ECPointMap pointMap, BigInteger[] ks) + { + int halfCount = ps.length, fullCount = halfCount << 1; + + boolean[] negs = new boolean[fullCount]; + WNafPreCompInfo[] infos = new WNafPreCompInfo[fullCount]; + byte[][] wnafs = new byte[fullCount][]; + + for (int i = 0; i < halfCount; ++i) + { + int j0 = i << 1, j1 = j0 + 1; + + BigInteger kj0 = ks[j0]; negs[j0] = kj0.signum() < 0; kj0 = kj0.abs(); + BigInteger kj1 = ks[j1]; negs[j1] = kj1.signum() < 0; kj1 = kj1.abs(); + + int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(kj0.bitLength(), kj1.bitLength())))); + + ECPoint P = ps[i], Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMap); + infos[j0] = WNafUtil.getWNafPreCompInfo(P); + infos[j1] = WNafUtil.getWNafPreCompInfo(Q); + wnafs[j0] = WNafUtil.generateWindowNaf(width, kj0); + wnafs[j1] = WNafUtil.generateWindowNaf(width, kj1); + } + + return implSumOfMultiplies(negs, infos, wnafs); + } + + private static ECPoint implSumOfMultiplies(boolean[] negs, WNafPreCompInfo[] infos, byte[][] wnafs) + { + int len = 0, count = wnafs.length; + for (int i = 0; i < count; ++i) + { len = Math.max(len, wnafs[i].length); } - ECCurve curve = ps[0].getCurve(); + ECCurve curve = infos[0].getPreComp()[0].getCurve(); ECPoint infinity = curve.getInfinity(); ECPoint R = infinity; @@ -276,7 +395,7 @@ public class ECAlgorithms { int n = Math.abs(wi); WNafPreCompInfo info = infos[j]; - ECPoint[] table = wi < 0 ? info.getPreCompNeg() : info.getPreComp(); + ECPoint[] table = (wi < 0 == negs[j]) ? info.getPreComp() : info.getPreCompNeg(); r = r.add(table[n >>> 1]); } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java b/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java index 11cc2683..066c950b 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java +++ b/core/src/main/java/org/bouncycastle/math/ec/ECCurve.java @@ -4,6 +4,8 @@ import java.math.BigInteger; import java.util.Hashtable; import java.util.Random; +import org.bouncycastle.math.ec.endo.ECEndomorphism; +import org.bouncycastle.math.ec.endo.GLVEndomorphism; import org.bouncycastle.math.field.FiniteField; import org.bouncycastle.math.field.FiniteFields; import org.bouncycastle.util.BigIntegers; @@ -32,11 +34,13 @@ public abstract class ECCurve public class Config { protected int coord; + protected ECEndomorphism endomorphism; protected ECMultiplier multiplier; - Config(int coord, ECMultiplier multiplier) + Config(int coord, ECEndomorphism endomorphism, ECMultiplier multiplier) { this.coord = coord; + this.endomorphism = endomorphism; this.multiplier = multiplier; } @@ -46,6 +50,12 @@ public abstract class ECCurve return this; } + public Config setEndomorphism(ECEndomorphism endomorphism) + { + this.endomorphism = endomorphism; + return this; + } + public Config setMultiplier(ECMultiplier multiplier) { this.multiplier = multiplier; @@ -66,6 +76,7 @@ public abstract class ECCurve } c.coord = coord; + c.endomorphism = endomorphism; c.multiplier = multiplier; return c; @@ -77,6 +88,7 @@ public abstract class ECCurve protected BigInteger order, cofactor; protected int coord = COORD_AFFINE; + protected ECEndomorphism endomorphism = null; protected ECMultiplier multiplier = null; protected ECCurve(FiniteField field) @@ -90,7 +102,7 @@ public abstract class ECCurve public Config configure() { - return new Config(this.coord, this.multiplier); + return new Config(this.coord, this.endomorphism, this.multiplier); } public ECPoint createPoint(BigInteger x, BigInteger y) @@ -111,8 +123,15 @@ public abstract class ECCurve protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression); + protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression); + protected ECMultiplier createDefaultMultiplier() { + if (endomorphism instanceof GLVEndomorphism) + { + return new GLVMultiplier(this, (GLVEndomorphism)endomorphism); + } + return new WNafL2RMultiplier(); } @@ -257,6 +276,11 @@ public abstract class ECCurve protected abstract ECPoint decompressPoint(int yTilde, BigInteger X1); + public ECEndomorphism getEndomorphism() + { + return endomorphism; + } + /** * Sets the default <code>ECMultiplier</code>, unless already set. */ @@ -463,6 +487,11 @@ public abstract class ECCurve return new ECPoint.Fp(this, x, y, withCompression); } + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new ECPoint.Fp(this, x, y, zs, withCompression); + } + public ECPoint importPoint(ECPoint p) { if (this != p.getCurve() && this.getCoordinateSystem() == COORD_JACOBIAN && !p.isInfinity()) @@ -824,6 +853,11 @@ public abstract class ECCurve return new ECPoint.F2m(this, x, y, withCompression); } + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new ECPoint.F2m(this, x, y, zs, withCompression); + } + public ECPoint getInfinity() { return infinity; diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java index 58a52b79..434287d9 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java +++ b/core/src/main/java/org/bouncycastle/math/ec/ECFieldElement.java @@ -220,6 +220,11 @@ public abstract class ECFieldElement */ public ECFieldElement sqrt() { + if (isZero() || isOne()) + { + return this; + } + if (!q.testBit(0)) { throw new RuntimeException("not done yet"); @@ -227,30 +232,45 @@ public abstract class ECFieldElement // note: even though this class implements ECConstants don't be tempted to // remove the explicit declaration, some J2ME environments don't cope. - // p mod 4 == 3 - if (q.testBit(1)) + + if (q.testBit(1)) // q == 4m + 3 { - // z = g^(u+1) + p, p = 4u + 3 - ECFieldElement z = new Fp(q, r, x.modPow(q.shiftRight(2).add(ECConstants.ONE), q)); + BigInteger e = q.shiftRight(2).add(ECConstants.ONE); + return checkSqrt(new Fp(q, r, x.modPow(e, q))); + } + + if (q.testBit(2)) // q == 8m + 5 + { + BigInteger t1 = x.modPow(q.shiftRight(3), q); + BigInteger t2 = modMult(t1, x); + BigInteger t3 = modMult(t2, t1); - return z.square().equals(this) ? z : null; + if (t3.equals(ECConstants.ONE)) + { + return checkSqrt(new Fp(q, r, t2)); + } + + // TODO This is constant and could be precomputed + BigInteger t4 = ECConstants.TWO.modPow(q.shiftRight(2), q); + + BigInteger y = modMult(t2, t4); + + return checkSqrt(new Fp(q, r, y)); } - // p mod 4 == 1 - BigInteger qMinusOne = q.subtract(ECConstants.ONE); + // q == 8m + 1 - BigInteger legendreExponent = qMinusOne.shiftRight(1); + BigInteger legendreExponent = q.shiftRight(1); if (!(x.modPow(legendreExponent, q).equals(ECConstants.ONE))) { return null; } - BigInteger u = qMinusOne.shiftRight(2); - BigInteger k = u.shiftLeft(1).add(ECConstants.ONE); - BigInteger X = this.x; BigInteger fourX = modDouble(modDouble(X)); + BigInteger k = legendreExponent.add(ECConstants.ONE), qMinusOne = q.subtract(ECConstants.ONE); + BigInteger U, V; Random rand = new Random(); do @@ -261,7 +281,7 @@ public abstract class ECFieldElement P = new BigInteger(q.bitLength(), rand); } while (P.compareTo(q) >= 0 - || !(modMult(P, P).subtract(fourX).modPow(legendreExponent, q).equals(qMinusOne))); + || !modReduce(P.multiply(P).subtract(fourX)).modPow(legendreExponent, q).equals(qMinusOne)); BigInteger[] result = lucasSequence(P, X, k); U = result[0]; @@ -269,17 +289,7 @@ public abstract class ECFieldElement if (modMult(V, V).equals(fourX)) { - // Integer division by 2, mod q - if (V.testBit(0)) - { - V = V.add(q); - } - - V = V.shiftRight(1); - - //assert modMult(V, V).equals(X); - - return new ECFieldElement.Fp(q, r, V); + return new ECFieldElement.Fp(q, r, modHalfAbs(V)); } } while (U.equals(ECConstants.ONE) || U.equals(qMinusOne)); @@ -287,6 +297,11 @@ public abstract class ECFieldElement return null; } + private ECFieldElement checkSqrt(ECFieldElement z) + { + return z.square().equals(this) ? z : null; + } + private BigInteger[] lucasSequence( BigInteger P, BigInteger Q, @@ -361,6 +376,24 @@ public abstract class ECFieldElement return _2x; } + protected BigInteger modHalf(BigInteger x) + { + if (x.testBit(0)) + { + x = q.add(x); + } + return x.shiftRight(1); + } + + protected BigInteger modHalfAbs(BigInteger x) + { + if (x.testBit(0)) + { + x = q.subtract(x); + } + return x.shiftRight(1); + } + protected BigInteger modInverse(BigInteger x) { int bits = getFieldSize(); diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java b/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java index 7bf2d336..2aa0fd21 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java +++ b/core/src/main/java/org/bouncycastle/math/ec/ECPoint.java @@ -284,6 +284,20 @@ public abstract class ECPoint return this.withCompression; } + public ECPoint scaleX(ECFieldElement scale) + { + return isInfinity() + ? this + : getCurve().createRawPoint(getRawXCoord().multiply(scale), getRawYCoord(), getRawZCoords(), this.withCompression); + } + + public ECPoint scaleY(ECFieldElement scale) + { + return isInfinity() + ? this + : getCurve().createRawPoint(getRawXCoord(), getRawYCoord().multiply(scale), getRawZCoords(), this.withCompression); + } + public boolean equals(ECPoint other) { if (null == other) @@ -1335,6 +1349,74 @@ public abstract class ECPoint } } + public ECPoint scaleX(ECFieldElement scale) + { + if (this.isInfinity()) + { + return this; + } + + int coord = this.getCurveCoordinateSystem(); + + switch (coord) + { + case ECCurve.COORD_LAMBDA_AFFINE: + { + // Y is actually Lambda (X + Y/X) here + ECFieldElement X = getRawXCoord(), L = getRawYCoord(); + + ECFieldElement X2 = X.multiply(scale); + ECFieldElement L2 = L.add(X).divide(scale).add(X2); + + return getCurve().createRawPoint(X, L2, getRawZCoords(), this.withCompression); + } + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + // Y is actually Lambda (X + Y/X) here + ECFieldElement X = getRawXCoord(), L = getRawYCoord(), Z = getRawZCoords()[0]; + + // We scale the Z coordinate also, to avoid an inversion + ECFieldElement X2 = X.multiply(scale.square()); + ECFieldElement L2 = L.add(X).add(X2); + ECFieldElement Z2 = Z.multiply(scale); + + return getCurve().createRawPoint(X2, L2, new ECFieldElement[]{ Z2 }, this.withCompression); + } + default: + { + return super.scaleX(scale); + } + } + } + + public ECPoint scaleY(ECFieldElement scale) + { + if (this.isInfinity()) + { + return this; + } + + int coord = this.getCurveCoordinateSystem(); + + switch (coord) + { + case ECCurve.COORD_LAMBDA_AFFINE: + case ECCurve.COORD_LAMBDA_PROJECTIVE: + { + ECFieldElement X = getRawXCoord(), L = getRawYCoord(); + + // Y is actually Lambda (X + Y/X) here + ECFieldElement L2 = L.add(X).multiply(scale).add(X); + + return getCurve().createRawPoint(X, L2, getRawZCoords(), this.withCompression); + } + default: + { + return super.scaleY(scale); + } + } + } + protected boolean getCompressionYTilde() { ECFieldElement X = this.getRawXCoord(); diff --git a/core/src/main/java/org/bouncycastle/math/ec/ECPointMap.java b/core/src/main/java/org/bouncycastle/math/ec/ECPointMap.java new file mode 100644 index 00000000..439e8daa --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/ECPointMap.java @@ -0,0 +1,6 @@ +package org.bouncycastle.math.ec; + +public interface ECPointMap +{ + ECPoint map(ECPoint p); +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java b/core/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java index 84fbf6a5..d2cc2e3b 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java +++ b/core/src/main/java/org/bouncycastle/math/ec/FixedPointCombMultiplier.java @@ -20,8 +20,7 @@ public class FixedPointCombMultiplier extends AbstractECMultiplier throw new IllegalStateException("fixed-point comb doesn't support scalars larger than the curve order"); } - // TODO Call method to let subclasses select width - int width = size > 257 ? 6 : 5; + int width = getWidthForCombSize(size); FixedPointPreCompInfo info = FixedPointUtil.precompute(p, width); ECPoint[] lookupTable = info.getPreComp(); @@ -49,4 +48,9 @@ public class FixedPointCombMultiplier extends AbstractECMultiplier return R; } + + protected int getWidthForCombSize(int combSize) + { + return combSize > 257 ? 6 : 5; + } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java b/core/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java new file mode 100644 index 00000000..09b83668 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/GLVMultiplier.java @@ -0,0 +1,42 @@ +package org.bouncycastle.math.ec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.endo.GLVEndomorphism; + +public class GLVMultiplier extends AbstractECMultiplier +{ + protected final ECCurve curve; + protected final GLVEndomorphism glvEndomorphism; + + public GLVMultiplier(ECCurve curve, GLVEndomorphism glvEndomorphism) + { + if (curve == null || curve.getOrder() == null) + { + throw new IllegalArgumentException("Need curve with known group order"); + } + + this.curve = curve; + this.glvEndomorphism = glvEndomorphism; + } + + protected ECPoint multiplyPositive(ECPoint p, BigInteger k) + { + if (!curve.equals(p.getCurve())) + { + throw new IllegalStateException(); + } + + BigInteger n = p.getCurve().getOrder(); + BigInteger[] ab = glvEndomorphism.decomposeScalar(k.mod(n)); + BigInteger a = ab[0], b = ab[1]; + + ECPointMap pointMap = glvEndomorphism.getPointMap(); + if (glvEndomorphism.hasEfficientPointMap()) + { + return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap, b); + } + + return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap.map(p), b); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/Mod.java b/core/src/main/java/org/bouncycastle/math/ec/Mod.java index 2ac6c465..0345af19 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/Mod.java +++ b/core/src/main/java/org/bouncycastle/math/ec/Mod.java @@ -1,5 +1,9 @@ package org.bouncycastle.math.ec; +import java.util.Random; + +import org.bouncycastle.crypto.util.Pack; + public abstract class Mod { public static void invert(int[] p, int[] x, int[] z) @@ -70,6 +74,31 @@ public abstract class Mod } } + public static int[] random(int[] p) + { + int len = p.length; + Random rand = new Random(); + int[] s = Nat.create(len); + + int m = p[len - 1]; + m |= m >>> 1; + m |= m >>> 2; + m |= m >>> 4; + m |= m >>> 8; + m |= m >>> 16; + + do + { + byte[] bytes = new byte[len << 2]; + rand. nextBytes(bytes); + Pack.bigEndianToInt(bytes, 0, s); + s[len - 1] &= m; + } + while (Nat.gte(len, s, p)); + + return s; + } + public static void subtract(int[] p, int[] x, int[] y, int[] z) { int len = p.length; diff --git a/core/src/main/java/org/bouncycastle/math/ec/Nat.java b/core/src/main/java/org/bouncycastle/math/ec/Nat.java index 6915b79b..9f85e8bc 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/Nat.java +++ b/core/src/main/java/org/bouncycastle/math/ec/Nat.java @@ -20,6 +20,52 @@ public abstract class Nat return (int)c; } + public static int add33At(int len, int x, int[] z, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zPos + 0] & M) + (x & M); + z[zPos + 0] = (int)c; + c >>>= 32; + c += (z[zPos + 1] & M) + 1L; + z[zPos + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zPos + 2); + } + + public static int add33At(int len, int x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zOff + zPos] & M) + (x & M); + z[zOff + zPos] = (int)c; + c >>>= 32; + c += (z[zOff + zPos + 1] & M) + 1L; + z[zOff + zPos + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2); + } + + public static int add33To(int len, int x, int[] z) + { + long c = (z[0] & M) + (x & M); + z[0] = (int)c; + c >>>= 32; + c += (z[1] & M) + 1L; + z[1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, 2); + } + + public static int add33To(int len, int x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) + (x & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (z[zOff + 1] & M) + 1L; + z[zOff + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, 2); + } + public static int addBothTo(int len, int[] x, int[] y, int[] z) { long c = 0; @@ -44,18 +90,62 @@ public abstract class Nat return (int)c; } - // TODO Re-write to allow full range for x? - public static int addDWord(int len, long x, int[] z, int zOff) + public static int addDWordAt(int len, long x, int[] z, int zPos) { - // assert zOff <= (len - 2); - long c = x; - c += (z[zOff + 0] & M); + // assert zPos <= (len - 2); + long c = (z[zPos + 0] & M) + (x & M); + z[zPos + 0] = (int)c; + c >>>= 32; + c += (z[zPos + 1] & M) + (x >>> 32); + z[zPos + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zPos + 2); + } + + public static int addDWordAt(int len, long x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zOff + zPos] & M) + (x & M); + z[zOff + zPos] = (int)c; + c >>>= 32; + c += (z[zOff + zPos + 1] & M) + (x >>> 32); + z[zOff + zPos + 1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, zPos + 2); + } + + public static int addDWordTo(int len, long x, int[] z) + { + long c = (z[0] & M) + (x & M); + z[0] = (int)c; + c >>>= 32; + c += (z[1] & M) + (x >>> 32); + z[1] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, 2); + } + + public static int addDWordTo(int len, long x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) + (x & M); z[zOff + 0] = (int)c; c >>>= 32; - c += (z[zOff + 1] & M); + c += (z[zOff + 1] & M) + (x >>> 32); z[zOff + 1] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(len, z, zOff + 2); + return c == 0 ? 0 : incAt(len, z, zOff, 2); + } + + public static int addTo(int len, int[] x, int[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[i] & M) + (z[i] & M); + z[i] = (int)c; + c >>>= 32; + } + return (int)c; } public static int addTo(int len, int[] x, int xOff, int[] z, int zOff) @@ -70,22 +160,38 @@ public abstract class Nat return (int)c; } - public static int addWord(int len, int x, int[] z) + public static int addWordAt(int len, int x, int[] z, int zPos) + { + // assert zPos <= (len - 1); + long c = (x & M) + (z[zPos] & M); + z[zPos] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zPos + 1); + } + + public static int addWordAt(int len, int x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 1); + long c = (x & M) + (z[zOff + zPos] & M); + z[zOff + zPos] = (int)c; + c >>>= 32; + return c == 0 ? 0 : incAt(len, z, zOff, zPos + 1); + } + + public static int addWordTo(int len, int x, int[] z) { long c = (x & M) + (z[0] & M); z[0] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(len, z, 1); + return c == 0 ? 0 : incAt(len, z, 1); } - public static int addWordExt(int len, int x, int[] zz, int zzOff) + public static int addWordTo(int len, int x, int[] z, int zOff) { - int extLen = len << 1; - // assert zzOff <= (extLen - 1); - long c = (x & M) + (zz[zzOff + 0] & M); - zz[zzOff + 0] = (int)c; + long c = (x & M) + (z[zOff] & M); + z[zOff] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(extLen, zz, zzOff + 1); + return c == 0 ? 0 : incAt(len, z, zOff, 1); } public static int[] copy(int len, int[] x) @@ -95,15 +201,53 @@ public abstract class Nat return z; } + public static void copy(int len, int[] x, int[] z) + { + System.arraycopy(x, 0, z, 0, len); + } + public static int[] create(int len) { return new int[len]; } - public static int dec(int len, int[] z, int zOff) + public static int dec(int len, int[] z) + { + for (int i = 0; i < len; ++i) + { + if (--z[i] != -1) + { + return 0; + } + } + return -1; + } + + public static int dec(int len, int[] x, int[] z) + { + int i = 0; + while (i < len) + { + int c = x[i] - 1; + z[i] = c; + ++i; + if (c != -1) + { + while (i < len) + { + z[i] = x[i]; + ++i; + } + return 0; + } + } + return -1; + } + + public static int decAt(int len, int[] z, int zPos) { - // assert zOff <= len; - for (int i = zOff; i < len; ++i) + // assert zPos <= len; + for (int i = zPos; i < len; ++i) { if (--z[i] != -1) { @@ -113,6 +257,19 @@ public abstract class Nat return -1; } + public static int decAt(int len, int[] z, int zOff, int zPos) + { + // assert zPos <= len; + for (int i = zPos; i < len; ++i) + { + if (--z[zOff + i] != -1) + { + return 0; + } + } + return -1; + } + public static boolean eq(int len, int[] x, int[] y) { for (int i = len - 1; i >= 0; --i) @@ -172,10 +329,43 @@ public abstract class Nat return true; } - public static int inc(int len, int[] z, int zOff) + public static int inc(int len, int[] z) + { + for (int i = 0; i < len; ++i) + { + if (++z[i] != 0) + { + return 0; + } + } + return 1; + } + + public static int inc(int len, int[] x, int[] z) { - // assert zOff <= len; - for (int i = zOff; i < len; ++i) + int i = 0; + while (i < len) + { + int c = x[i] + 1; + z[i] = c; + ++i; + if (c != 0) + { + while (i < len) + { + z[i] = x[i]; + ++i; + } + return 0; + } + } + return 1; + } + + public static int incAt(int len, int[] z, int zPos) + { + // assert zPos <= len; + for (int i = zPos; i < len; ++i) { if (++z[i] != 0) { @@ -185,6 +375,19 @@ public abstract class Nat return 1; } + public static int incAt(int len, int[] z, int zOff, int zPos) + { + // assert zPos <= len; + for (int i = zPos; i < len; ++i) + { + if (++z[zOff + i] != 0) + { + return 0; + } + } + return 1; + } + public static boolean isOne(int len, int[] x) { if (x[0] != 1) @@ -215,14 +418,51 @@ public abstract class Nat public static void mul(int len, int[] x, int[] y, int[] zz) { - zz[len] = mulWord(len, x[0], y, zz, 0); + zz[len] = mulWord(len, x[0], y, zz); for (int i = 1; i < len; ++i) { - zz[i + len] = mulWordAdd(len, x[i], y, zz, i); + zz[i + len] = mulWordAddTo(len, x[i], y, 0, zz, i); } } + public static void mul(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + zz[zzOff + len] = mulWord(len, x[xOff], y, yOff, zz, zzOff); + + for (int i = 1; i < len; ++i) + { + zz[zzOff + i + len] = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff + i); + } + } + + public static int mulAddTo(int len, int[] x, int[] y, int[] zz) + { + long zc = 0; + for (int i = 0; i < len; ++i) + { + long c = mulWordAddTo(len, x[i], y, 0, zz, i) & M; + c += zc + (zz[i + len] & M); + zz[i + len] = (int)c; + zc = c >>> 32; + } + return (int)zc; + } + + public static int mulAddTo(int len, int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long zc = 0; + for (int i = 0; i < len; ++i) + { + long c = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff) & M; + c += zc + (zz[zzOff + len] & M); + zz[zzOff + len] = (int)c; + zc = c >>> 32; + ++zzOff; + } + return (int)zc; + } + public static int mul31BothAdd(int len, int a, int[] x, int b, int[] y, int[] z, int zOff) { long c = 0, aVal = a & M, bVal = b & M; @@ -237,13 +477,27 @@ public abstract class Nat return (int)c; } - public static int mulWord(int len, int x, int[] y, int[] z, int zOff) + public static int mulWord(int len, int x, int[] y, int[] z) { long c = 0, xVal = x & M; int i = 0; do { c += xVal * (y[i] & M); + z[i] = (int)c; + c >>>= 32; + } + while (++i < len); + return (int)c; + } + + public static int mulWord(int len, int x, int[] y, int yOff, int[] z, int zOff) + { + long c = 0, xVal = x & M; + int i = 0; + do + { + c += xVal * (y[yOff + i] & M); z[zOff + i] = (int)c; c >>>= 32; } @@ -251,13 +505,13 @@ public abstract class Nat return (int)c; } - public static int mulWordAdd(int len, int x, int[] y, int[] z, int zOff) + public static int mulWordAddTo(int len, int x, int[] y, int yOff, int[] z, int zOff) { long c = 0, xVal = x & M; int i = 0; do { - c += xVal * (y[i] & M) + (z[zOff + i] & M); + c += xVal * (y[yOff + i] & M) + (z[zOff + i] & M); z[zOff + i] = (int)c; c >>>= 32; } @@ -265,20 +519,20 @@ public abstract class Nat return (int)c; } - public static int mulWordDwordAdd(int len, int x, long y, int[] z, int zOff) + public static int mulWordDwordAddAt(int len, int x, long y, int[] z, int zPos) { - // assert zOff <= (len - 3); + // assert zPos <= (len - 3); long c = 0, xVal = x & M; - c += xVal * (y & M) + (z[zOff + 0] & M); - z[zOff + 0] = (int)c; + c += xVal * (y & M) + (z[zPos + 0] & M); + z[zPos + 0] = (int)c; c >>>= 32; - c += xVal * (y >>> 32) + (z[zOff + 1] & M); - z[zOff + 1] = (int)c; + c += xVal * (y >>> 32) + (z[zPos + 1] & M); + z[zPos + 1] = (int)c; c >>>= 32; - c += (z[zOff + 2] & M); - z[zOff + 2] = (int)c; + c += (z[zPos + 2] & M); + z[zPos + 2] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(len, z, zOff + 3); + return c == 0 ? 0 : incAt(len, z, zPos + 3); } public static int shiftDownBit(int len, int[] z, int c) @@ -293,6 +547,18 @@ public abstract class Nat return c << 31; } + public static int shiftDownBit(int len, int[] z, int zOff, int c) + { + int i = len; + while (--i >= 0) + { + int next = z[zOff + i]; + z[zOff + i] = (next >>> 1) | (c << 31); + c = next; + } + return c << 31; + } + public static int shiftDownBit(int len, int[] x, int c, int[] z) { int i = len; @@ -305,6 +571,18 @@ public abstract class Nat return c << 31; } + public static int shiftDownBit(int len, int[] x, int xOff, int c, int[] z, int zOff) + { + int i = len; + while (--i >= 0) + { + int next = x[xOff + i]; + z[zOff + i] = (next >>> 1) | (c << 31); + c = next; + } + return c << 31; + } + public static int shiftDownBits(int len, int[] z, int bits, int c) { // assert bits > 0 && bits < 32; @@ -318,19 +596,45 @@ public abstract class Nat return c << -bits; } - public static int shiftDownBits(int len, int[] x, int xOff, int bits, int c, int[] z) + public static int shiftDownBits(int len, int[] z, int zOff, int bits, int c) { // assert bits > 0 && bits < 32; int i = len; while (--i >= 0) { - int next = x[xOff + i]; + int next = z[zOff + i]; + z[zOff + i] = (next >>> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + + public static int shiftDownBits(int len, int[] x, int bits, int c, int[] z) + { +// assert bits > 0 && bits < 32; + int i = len; + while (--i >= 0) + { + int next = x[i]; z[i] = (next >>> bits) | (c << -bits); c = next; } return c << -bits; } + public static int shiftDownBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff) + { +// assert bits > 0 && bits < 32; + int i = len; + while (--i >= 0) + { + int next = x[xOff + i]; + z[zOff + i] = (next >>> bits) | (c << -bits); + c = next; + } + return c << -bits; + } + public static int shiftDownWord(int len, int[] z, int c) { int i = len; @@ -354,6 +658,17 @@ public abstract class Nat return c >>> 31; } + public static int shiftUpBit(int len, int[] z, int zOff, int c) + { + for (int i = 0; i < len; ++i) + { + int next = z[zOff + i]; + z[zOff + i] = (next << 1) | (c >>> 31); + c = next; + } + return c >>> 31; + } + public static int shiftUpBit(int len, int[] x, int c, int[] z) { for (int i = 0; i < len; ++i) @@ -365,12 +680,12 @@ public abstract class Nat return c >>> 31; } - public static int shiftUpBit(int len, int[] x, int xOff, int c, int[] z) + public static int shiftUpBit(int len, int[] x, int xOff, int c, int[] z, int zOff) { for (int i = 0; i < len; ++i) { int next = x[xOff + i]; - z[i] = (next << 1) | (c >>> 31); + z[zOff + i] = (next << 1) | (c >>> 31); c = next; } return c >>> 31; @@ -388,6 +703,18 @@ public abstract class Nat return c >>> -bits; } + public static int shiftUpBits(int len, int[] z, int zOff, int bits, int c) + { +// assert bits > 0 && bits < 32; + for (int i = 0; i < len; ++i) + { + int next = z[zOff + i]; + z[zOff + i] = (next << bits) | (c >>> -bits); + c = next; + } + return c >>> -bits; + } + public static int shiftUpBits(int len, int[] x, int bits, int c, int[] z) { // assert bits > 0 && bits < 32; @@ -400,6 +727,18 @@ public abstract class Nat return c >>> -bits; } + public static int shiftUpBits(int len, int[] x, int xOff, int bits, int c, int[] z, int zOff) + { +// assert bits > 0 && bits < 32; + for (int i = 0; i < len; ++i) + { + int next = x[xOff + i]; + z[zOff + i] = (next << bits) | (c >>> -bits); + c = next; + } + return c >>> -bits; + } + public static void square(int len, int[] x, int[] zz) { int extLen = len << 1; @@ -417,28 +756,66 @@ public abstract class Nat for (int i = 1; i < len; ++i) { - c = squareWordAddExt(len, x, i, zz); - addWordExt(len, c, zz, i << 1); + c = squareWordAdd(x, i, zz); + addWordAt(extLen, c, zz, i << 1); } shiftUpBit(extLen, zz, x[0] << 31); } - public static int squareWordAddExt(int len, int[] x, int xPos, int[] zz) + public static void square(int len, int[] x, int xOff, int[] zz, int zzOff) + { + int extLen = len << 1; + int c = 0; + int j = len, k = extLen; + do + { + long xVal = (x[xOff + --j] & M); + long p = xVal * xVal; + zz[zzOff + --k] = (c << 31) | (int)(p >>> 33); + zz[zzOff + --k] = (int)(p >>> 1); + c = (int)p; + } + while (j > 0); + + for (int i = 1; i < len; ++i) + { + c = squareWordAdd(x, xOff, i, zz, zzOff); + addWordAt(extLen, c, zz, zzOff, i << 1); + } + + shiftUpBit(extLen, zz, zzOff, x[xOff] << 31); + } + + public static int squareWordAdd(int[] x, int xPos, int[] z) { - // assert xPos > 0 && xPos < len; long c = 0, xVal = x[xPos] & M; int i = 0; do { - c += xVal * (x[i] & M) + (zz[xPos + i] & M); - zz[xPos + i] = (int)c; + c += xVal * (x[i] & M) + (z[xPos + i] & M); + z[xPos + i] = (int)c; c >>>= 32; } while (++i < xPos); return (int)c; } + public static int squareWordAdd(int[] x, int xOff, int xPos, int[] z, int zOff) + { + long c = 0, xVal = x[xOff + xPos] & M; + int i = 0; + do + { + c += xVal * (x[xOff + i] & M) + (z[xPos + zOff] & M); + z[xPos + zOff] = (int)c; + c >>>= 32; + ++zOff; + } + while (++i < xPos); + return (int)c; + } + public static int sub(int len, int[] x, int[] y, int[] z) { long c = 0; @@ -451,6 +828,64 @@ public abstract class Nat return (int)c; } + public static int sub(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[xOff + i] & M) - (y[yOff + i] & M); + z[zOff + i] = (int)c; + c >>= 32; + } + return (int)c; + } + + public static int sub33At(int len, int x, int[] z, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zPos + 0] & M) - (x & M); + z[zPos + 0] = (int)c; + c >>= 32; + c += (z[zPos + 1] & M) - 1; + z[zPos + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zPos + 2); + } + + public static int sub33At(int len, int x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zOff + zPos] & M) - (x & M); + z[zOff + zPos] = (int)c; + c >>= 32; + c += (z[zOff + zPos + 1] & M) - 1; + z[zOff + zPos + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, zPos + 2); + } + + public static int sub33From(int len, int x, int[] z) + { + long c = (z[0] & M) - (x & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - 1; + z[1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, 2); + } + + public static int sub33From(int len, int x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) - (x & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (z[zOff + 1] & M) - 1; + z[zOff + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, 2); + } + public static int subBothFrom(int len, int[] x, int[] y, int[] z) { long c = 0; @@ -475,18 +910,62 @@ public abstract class Nat return (int)c; } - // TODO Re-write to allow full range for x? - public static int subDWord(int len, long x, int[] z) + public static int subDWordAt(int len, long x, int[] z, int zPos) { - // assert 0 <= (len - 2); - long c = -x; - c += (z[0] & M); + // assert zPos <= (len - 2); + long c = (z[zPos + 0] & M) - (x & M); + z[zPos + 0] = (int)c; + c >>= 32; + c += (z[zPos + 1] & M) - (x >>> 32); + z[zPos + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zPos + 2); + } + + public static int subDWordAt(int len, long x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 2); + long c = (z[zOff + zPos] & M) - (x & M); + z[zOff + zPos] = (int)c; + c >>= 32; + c += (z[zOff + zPos + 1] & M) - (x >>> 32); + z[zOff + zPos + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, zPos + 2); + } + + public static int subDWordFrom(int len, long x, int[] z) + { + long c = (z[0] & M) - (x & M); z[0] = (int)c; c >>= 32; - c += (z[1] & M); + c += (z[1] & M) - (x >>> 32); z[1] = (int)c; c >>= 32; - return c == 0 ? 0 : dec(len, z, 2); + return c == 0 ? 0 : decAt(len, z, 2); + } + + public static int subDWordFrom(int len, long x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) - (x & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (z[zOff + 1] & M) - (x >>> 32); + z[zOff + 1] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, 2); + } + + public static int subFrom(int len, int[] x, int[] z) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (z[i] & M) - (x[i] & M); + z[i] = (int)c; + c >>= 32; + } + return (int)c; } public static int subFrom(int len, int[] x, int xOff, int[] z, int zOff) @@ -501,6 +980,40 @@ public abstract class Nat return (int)c; } + public static int subWordAt(int len, int x, int[] z, int zPos) + { + // assert zPos <= (len - 1); + long c = (z[zPos] & M) - (x & M); + z[zPos] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zPos + 1); + } + + public static int subWordAt(int len, int x, int[] z, int zOff, int zPos) + { + // assert zPos <= (len - 1); + long c = (z[zOff + zPos] & M) - (x & M); + z[zOff + zPos] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, zPos + 1); + } + + public static int subWordFrom(int len, int x, int[] z) + { + long c = (z[0] & M) - (x & M); + z[0] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, 1); + } + + public static int subWordFrom(int len, int x, int[] z, int zOff) + { + long c = (z[zOff + 0] & M) - (x & M); + z[zOff + 0] = (int)c; + c >>= 32; + return c == 0 ? 0 : decAt(len, z, zOff, 1); + } + public static BigInteger toBigInteger(int len, int[] x) { byte[] bs = new byte[len << 2]; diff --git a/core/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java b/core/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java new file mode 100644 index 00000000..099f5fb3 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/ScaleXPointMap.java @@ -0,0 +1,16 @@ +package org.bouncycastle.math.ec; + +public class ScaleXPointMap implements ECPointMap +{ + protected final ECFieldElement scale; + + public ScaleXPointMap(ECFieldElement scale) + { + this.scale = scale; + } + + public ECPoint map(ECPoint p) + { + return p.scaleX(scale); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/ScaleYPointMap.java b/core/src/main/java/org/bouncycastle/math/ec/ScaleYPointMap.java new file mode 100644 index 00000000..a7a87904 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/ScaleYPointMap.java @@ -0,0 +1,16 @@ +package org.bouncycastle.math.ec; + +public class ScaleYPointMap implements ECPointMap +{ + protected final ECFieldElement scale; + + public ScaleYPointMap(ECFieldElement scale) + { + this.scale = scale; + } + + public ECPoint map(ECPoint p) + { + return p.scaleY(scale); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java b/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java index f8020314..e1868f4d 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java +++ b/core/src/main/java/org/bouncycastle/math/ec/WNafUtil.java @@ -6,7 +6,10 @@ public abstract class WNafUtil { public static final String PRECOMP_NAME = "bc_wnaf"; - private static int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 }; + private static final int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 }; + + private static final byte[] EMPTY_BYTES = new byte[0]; + private static final int[] EMPTY_INTS = new int[0]; public static int[] generateCompactNaf(BigInteger k) { @@ -14,30 +17,35 @@ public abstract class WNafUtil { throw new IllegalArgumentException("'k' must have bitlength < 2^16"); } + if (k.signum() == 0) + { + return EMPTY_INTS; + } BigInteger _3k = k.shiftLeft(1).add(k); - int digits = _3k.bitLength() - 1; - int[] naf = new int[(digits + 1) >> 1]; + int bits = _3k.bitLength(); + int[] naf = new int[bits >> 1]; - int length = 0, zeroes = 0; - for (int i = 1; i <= digits; ++i) - { - boolean _3kBit = _3k.testBit(i); - boolean kBit = k.testBit(i); + BigInteger diff = _3k.xor(k); - if (_3kBit == kBit) + int highBit = bits - 1, length = 0, zeroes = 0; + for (int i = 1; i < highBit; ++i) + { + if (!diff.testBit(i)) { ++zeroes; + continue; } - else - { - int digit = kBit ? -1 : 1; - naf[length++] = (digit << 16) | zeroes; - zeroes = 0; - } + + int digit = k.testBit(i) ? -1 : 1; + naf[length++] = (digit << 16) | zeroes; + zeroes = 1; + ++i; } + naf[length++] = (1 << 16) | zeroes; + if (naf.length > length) { naf = trim(naf, length); @@ -61,6 +69,10 @@ public abstract class WNafUtil { throw new IllegalArgumentException("'k' must have bitlength < 2^16"); } + if (k.signum() == 0) + { + return EMPTY_INTS; + } int[] wnaf = new int[k.bitLength() / width + 1]; @@ -171,19 +183,29 @@ public abstract class WNafUtil public static byte[] generateNaf(BigInteger k) { + if (k.signum() == 0) + { + return EMPTY_BYTES; + } + BigInteger _3k = k.shiftLeft(1).add(k); int digits = _3k.bitLength() - 1; byte[] naf = new byte[digits]; - for (int i = 1; i <= digits; ++i) - { - boolean _3kBit = _3k.testBit(i); - boolean kBit = k.testBit(i); + BigInteger diff = _3k.xor(k); - naf[i - 1] = (byte)(_3kBit == kBit ? 0 : kBit ? -1 : 1); + for (int i = 1; i < digits; ++i) + { + if (diff.testBit(i)) + { + naf[i - 1] = (byte)(k.testBit(i) ? -1 : 1); + ++i; + } } + naf[digits - 1] = 1; + return naf; } @@ -210,6 +232,10 @@ public abstract class WNafUtil { throw new IllegalArgumentException("'width' must be in the range [2, 8]"); } + if (k.signum() == 0) + { + return EMPTY_BYTES; + } byte[] wnaf = new byte[k.bitLength() + 1]; @@ -257,6 +283,11 @@ public abstract class WNafUtil return wnaf; } + public static WNafPreCompInfo getWNafPreCompInfo(ECPoint p) + { + return getWNafPreCompInfo(p.getCurve().getPreCompInfo(p, PRECOMP_NAME)); + } + public static WNafPreCompInfo getWNafPreCompInfo(PreCompInfo preCompInfo) { if ((preCompInfo != null) && (preCompInfo instanceof WNafPreCompInfo)) @@ -298,6 +329,45 @@ public abstract class WNafUtil return w + 2; } + public static ECPoint mapPointWithPrecomp(ECPoint p, int width, boolean includeNegated, + ECPointMap pointMap) + { + ECCurve c = p.getCurve(); + WNafPreCompInfo wnafPreCompP = precompute(p, width, includeNegated); + + ECPoint q = pointMap.map(p); + WNafPreCompInfo wnafPreCompQ = getWNafPreCompInfo(c.getPreCompInfo(q, PRECOMP_NAME)); + + ECPoint twiceP = wnafPreCompP.getTwice(); + if (twiceP != null) + { + ECPoint twiceQ = pointMap.map(twiceP); + wnafPreCompQ.setTwice(twiceQ); + } + + ECPoint[] preCompP = wnafPreCompP.getPreComp(); + ECPoint[] preCompQ = new ECPoint[preCompP.length]; + for (int i = 0; i < preCompP.length; ++i) + { + preCompQ[i] = pointMap.map(preCompP[i]); + } + wnafPreCompQ.setPreComp(preCompQ); + + if (includeNegated) + { + ECPoint[] preCompNegQ = new ECPoint[preCompQ.length]; + for (int i = 0; i < preCompNegQ.length; ++i) + { + preCompNegQ[i] = preCompQ[i].negate(); + } + wnafPreCompQ.setPreCompNeg(preCompNegQ); + } + + c.setPreCompInfo(q, PRECOMP_NAME, wnafPreCompQ); + + return q; + } + public static WNafPreCompInfo precompute(ECPoint p, int width, boolean includeNegated) { ECCurve c = p.getCurve(); @@ -324,7 +394,7 @@ public abstract class WNafUtil ECPoint twiceP = wnafPreCompInfo.getTwice(); if (twiceP == null) { - twiceP = preComp[0].twice().normalize(); + twiceP = preComp[0].twice(); wnafPreCompInfo.setTwice(twiceP); } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519.java b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519.java new file mode 100644 index 00000000..87802847 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519.java @@ -0,0 +1,105 @@ +package org.bouncycastle.math.ec.custom.djb; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.custom.sec.Nat256; +import org.bouncycastle.math.field.FiniteFields; +import org.bouncycastle.util.encoders.Hex; + +public class Curve25519 extends ECCurve +{ + public static final BigInteger q = Nat256.toBigInteger(Curve25519Field.P); + + private static final int Curve25519_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED; + + protected Curve25519Point infinity; + + public Curve25519() + { + super(FiniteFields.getPrimeField(q)); + + this.infinity = new Curve25519Point(this, null, null); + + this.a = fromBigInteger(new BigInteger(1, + Hex.decode("2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144"))); + this.b = fromBigInteger(new BigInteger(1, + Hex.decode("7B425ED097B425ED097B425ED097B425ED097B425ED097B4260B5E9C7710C864"))); + this.order = new BigInteger(1, Hex.decode("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED")); + this.cofactor = BigInteger.valueOf(8); + + this.coord = Curve25519_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new Curve25519(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN_MODIFIED: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new Curve25519FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new Curve25519Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new Curve25519Point(this, x, y, zs, withCompression); + } + + protected ECPoint decompressPoint(int yTilde, BigInteger X1) + { + ECFieldElement x = fromBigInteger(X1); + ECFieldElement alpha = x.square().add(getA()).multiply(x).add(getB()); + ECFieldElement beta = alpha.sqrt(); + + // + // if we can't find a sqrt we haven't got a point on the + // curve - run! + // + if (beta == null) + { + throw new RuntimeException("Invalid point compression"); + } + + if (beta.testBitZero() != (yTilde == 1)) + { + // Use the other root + beta = beta.negate(); + } + + return new Curve25519Point(this, x, beta, true); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Curve25519Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Field.java index 5cf9fea8..663e2fb3 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Curve25519Field.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Field.java @@ -1,11 +1,14 @@ -package org.bouncycastle.math.ec.custom.sec; +package org.bouncycastle.math.ec.custom.djb; import java.math.BigInteger; import org.bouncycastle.math.ec.Nat; +import org.bouncycastle.math.ec.custom.sec.Nat256; public class Curve25519Field { + private static final long M = 0xFFFFFFFFL; + // 2^255 - 2^4 - 2^1 - 1 static final int[] P = new int[]{ 0xFFFFFFED, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF }; @@ -20,38 +23,34 @@ public class Curve25519Field Nat256.add(x, y, z); if (Nat256.gte(z, P)) { - Nat256.addWord(PInv, z, 0); - z[7] &= P7; + addPInvTo(z); } } public static void addExt(int[] xx, int[] yy, int[] zz) { - Nat256.addExt(xx, yy, zz); - if (Nat256.gteExt(zz, PExt)) + Nat.add(16, xx, yy, zz); + if (Nat.gte(16, zz, PExt)) { - Nat256.subExt(zz, PExt, zz); + subPExtFrom(zz); } } public static void addOne(int[] x, int[] z) { - Nat256.copy(x, z); - Nat256.inc(z, 0); + Nat.inc(8, x, z); if (Nat256.gte(z, P)) { - Nat256.addWord(PInv, z, 0); - z[7] &= P7; + addPInvTo(z); } } public static int[] fromBigInteger(BigInteger x) { int[] z = Nat256.fromBigInteger(x); - if (Nat256.gte(z, P)) + while (Nat256.gte(z, P)) { - Nat256.addWord(PInv, z, 0); - z[7] &= P7; + Nat256.subFrom(P, z); } return z; } @@ -93,16 +92,15 @@ public class Curve25519Field // assert xx[15] >>> 30 == 0; int xx07 = xx[7]; - Nat.shiftUpBit(8, xx, 8, xx07, z); + Nat.shiftUpBit(8, xx, 8, xx07, z, 0); int c = Nat256.mulByWordAddTo(PInv, xx, z) << 1; int z07 = z[7]; z[7] = z07 & P7; c += (z07 >>> 31) - (xx07 >>> 31); - Nat256.addWord(c * PInv, z, 0); + Nat.addWordTo(8, c * PInv, z); if (Nat256.gte(z, P)) { - Nat256.addWord(PInv, z, 0); - z[7] &= P7; + addPInvTo(z); } } @@ -133,27 +131,83 @@ public class Curve25519Field int c = Nat256.sub(x, y, z); if (c != 0) { - Nat256.subWord(PInv, z, 0); - z[7] &= P7; + subPInvFrom(z); } } public static void subtractExt(int[] xx, int[] yy, int[] zz) { - int c = Nat256.subExt(xx, yy, zz); + int c = Nat.sub(16, xx, yy, zz); if (c != 0) { - Nat256.addExt(zz, PExt, zz); + addPExtTo(zz); } } public static void twice(int[] x, int[] z) { - Nat256.shiftUpBit(x, 0, z); + Nat.shiftUpBit(8, x, 0, z); if (Nat256.gte(z, P)) { - Nat256.addWord(PInv, z, 0); - z[7] &= P7; + addPInvTo(z); + } + } + + private static void addPExtTo(int[] zz) + { + long c = (zz[0] & M) + (PExt[0] & M); + zz[0] = (int)c; + c >>= 32; + + int i = 1 - (int)c; + i = (i << 3) - i; + + while (++i < 16) + { + c += (zz[i] & M) + (PExt[i] & M); + zz[i] = (int)c; + c >>= 32; + } + } + + private static void subPExtFrom(int[] zz) + { + long c = (zz[0] & M) - (PExt[0] & M); + zz[0] = (int)c; + c >>= 32; + + int i = 1 + (int)c; + i = (i << 3) - i; + + while (++i < 16) + { + c += (zz[i] & M) - (PExt[i] & M); + zz[i] = (int)c; + c >>= 32; + } + } + + private static void addPInvTo(int[] z) + { + long c = (z[0] & M) + PInv; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.incAt(8, z, 1); + } + z[7] &= P7; + } + + private static void subPInvFrom(int[] z) + { + long c = (z[0] & M) - PInv; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.decAt(8, z, 1); } + z[7] &= P7; } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java new file mode 100644 index 00000000..6e3d9cfa --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java @@ -0,0 +1,234 @@ +package org.bouncycastle.math.ec.custom.djb; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.Mod; +import org.bouncycastle.math.ec.custom.sec.Nat256; +import org.bouncycastle.util.Arrays; + +public class Curve25519FieldElement extends ECFieldElement +{ + public static final BigInteger Q = Curve25519.q; + + // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q) + private static final int[] PRECOMP_POW2 = new int[]{ 0x4a0ea0b0, 0xc4ee1b27, 0xad2fe478, 0x2f431806, + 0x3dfbd7a7, 0x2b4d0099, 0x4fc1df0b, 0x2b832480 }; + + protected int[] x; + + public Curve25519FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for Curve25519FieldElement"); + } + + this.x = Curve25519Field.fromBigInteger(x); + } + + public Curve25519FieldElement() + { + this.x = Nat256.create(); + } + + protected Curve25519FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat256.isZero(x); + } + + public boolean isOne() + { + return Nat256.isOne(x); + } + + public boolean testBitZero() + { + return Nat256.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat256.toBigInteger(x); + } + + public String getFieldName() + { + return "Curve25519Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat256.create(); + Curve25519Field.add(x, ((Curve25519FieldElement)b).x, z); + return new Curve25519FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat256.create(); + Curve25519Field.addOne(x, z); + return new Curve25519FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat256.create(); + Curve25519Field.subtract(x, ((Curve25519FieldElement)b).x, z); + return new Curve25519FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat256.create(); + Curve25519Field.multiply(x, ((Curve25519FieldElement)b).x, z); + return new Curve25519FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat256.create(); + Mod.invert(Curve25519Field.P, ((Curve25519FieldElement)b).x, z); + Curve25519Field.multiply(z, x, z); + return new Curve25519FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat256.create(); + Curve25519Field.negate(x, z); + return new Curve25519FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat256.create(); + Curve25519Field.square(x, z); + return new Curve25519FieldElement(z); + } + + public ECFieldElement invert() + { +// return new Curve25519FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat256.create(); + Mod.invert(Curve25519Field.P, x, z); + return new Curve25519FieldElement(z); + } + + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + /* + * Q == 8m + 5, so we use Pocklington's method for this case. + * + * First, raise this element to the exponent 2^252 - 2^1 (i.e. m + 1) + * + * Breaking up the exponent's binary representation into "repunits", we get: + * { 251 1s } { 1 0s } + * + * Therefore we need an addition chain containing 251 (the lengths of the repunits) + * We use: 1, 2, 3, 4, 7, 11, 15, 30, 60, 120, 131, [251] + */ + + int[] x1 = this.x; + if (Nat256.isZero(x1) || Nat256.isOne(x1)) + { + return this; + } + + int[] x2 = Nat256.create(); + Curve25519Field.square(x1, x2); + Curve25519Field.multiply(x2, x1, x2); + int[] x3 = x2; + Curve25519Field.square(x2, x3); + Curve25519Field.multiply(x3, x1, x3); + int[] x4 = Nat256.create(); + Curve25519Field.square(x3, x4); + Curve25519Field.multiply(x4, x1, x4); + int[] x7 = Nat256.create(); + Curve25519Field.squareN(x4, 3, x7); + Curve25519Field.multiply(x7, x3, x7); + int[] x11 = x3; + Curve25519Field.squareN(x7, 4, x11); + Curve25519Field.multiply(x11, x4, x11); + int[] x15 = x7; + Curve25519Field.squareN(x11, 4, x15); + Curve25519Field.multiply(x15, x4, x15); + int[] x30 = x4; + Curve25519Field.squareN(x15, 15, x30); + Curve25519Field.multiply(x30, x15, x30); + int[] x60 = x15; + Curve25519Field.squareN(x30, 30, x60); + Curve25519Field.multiply(x60, x30, x60); + int[] x120 = x30; + Curve25519Field.squareN(x60, 60, x120); + Curve25519Field.multiply(x120, x60, x120); + int[] x131 = x60; + Curve25519Field.squareN(x120, 11, x131); + Curve25519Field.multiply(x131, x11, x131); + int[] x251 = x11; + Curve25519Field.squareN(x131, 120, x251); + Curve25519Field.multiply(x251, x120, x251); + + int[] t1 = x251; + Curve25519Field.square(t1, t1); + + int[] t2 = x120; + Curve25519Field.square(t1, t2); + + if (Nat256.eq(x1, t2)) + { + return new Curve25519FieldElement(t1); + } + + /* + * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess, + * which is ((4x)^(m + 1))/2 mod Q + */ + Curve25519Field.multiply(t1, PRECOMP_POW2, t1); + + Curve25519Field.square(t1, t2); + + if (Nat256.eq(x1, t2)) + { + return new Curve25519FieldElement(t1); + } + + return null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof Curve25519FieldElement)) + { + return false; + } + + Curve25519FieldElement o = (Curve25519FieldElement)other; + return Nat256.eq(x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 8); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java new file mode 100644 index 00000000..2913af99 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java @@ -0,0 +1,304 @@ +package org.bouncycastle.math.ec.custom.djb; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; + +public class Curve25519Point extends ECPoint +{ + /** + * Create a point which encodes with point compression. + * + * @param curve the curve to use + * @param x affine x co-ordinate + * @param y affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve the curve to use + * @param x affine x co-ordinate + * @param y affine y co-ordinate + * @param withCompression if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} + */ + public Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new Curve25519Point(null, getAffineXCoord(), getAffineYCoord()); + } + + protected boolean getCompressionYTilde() + { + return this.getAffineYCoord().testBitZero(); + } + + public ECFieldElement getZCoord(int index) + { + if (index == 1) + { + return getJacobianModifiedW(); + } + + return super.getZCoord(index); + } + + // B.3 pg 62 + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + ECFieldElement X1 = this.x, Y1 = this.y; + ECFieldElement X2 = b.getXCoord(), Y2 = b.getYCoord(); + + ECFieldElement Z1 = this.zs[0]; + ECFieldElement Z2 = b.getZCoord(0); + + boolean Z1IsOne = Z1.isOne(); + + ECFieldElement Z1Squared, U2, S2; + if (Z1IsOne) + { + Z1Squared = Z1; U2 = X2; S2 = Y2; + } + else + { + Z1Squared = Z1.square(); + U2 = Z1Squared.multiply(X2); + ECFieldElement Z1Cubed = Z1Squared.multiply(Z1); + S2 = Z1Cubed.multiply(Y2); + } + + boolean Z2IsOne = Z2.isOne(); + ECFieldElement Z2Squared, U1, S1; + if (Z2IsOne) + { + Z2Squared = Z2; U1 = X1; S1 = Y1; + } + else + { + Z2Squared = Z2.square(); + U1 = Z2Squared.multiply(X1); + ECFieldElement Z2Cubed = Z2Squared.multiply(Z2); + S1 = Z2Cubed.multiply(Y1); + } + + ECFieldElement H = U1.subtract(U2); + ECFieldElement R = S1.subtract(S2); + + // Check if b == this or b == -this + if (H.isZero()) + { + if (R.isZero()) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + ECFieldElement HSquared = H.square(); + ECFieldElement G = HSquared.multiply(H); + ECFieldElement V = HSquared.multiply(U1); + + ECFieldElement X3 = R.square().add(G).subtract(two(V)); + ECFieldElement Y3 = V.subtract(X3).multiplyMinusProduct(R, G, S1); + + ECFieldElement Z3 = H; + if (!Z1IsOne) + { + Z3 = Z3.multiply(Z1); + } + if (!Z2IsOne) + { + Z3 = Z3.multiply(Z2); + } + + ECFieldElement Z3Squared = (Z3 == H) ? HSquared : null; + + // TODO If the result will only be used in a subsequent addition, we don't need W3 + ECFieldElement W3 = calculateJacobianModifiedW(Z3, Z3Squared); + + ECFieldElement[] zs = new ECFieldElement[]{ Z3, W3 }; + + return new Curve25519Point(curve, X3, Y3, zs, this.withCompression); + } + + // B.3 pg 62 + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + return twiceJacobianModified(true); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twiceJacobianModified(false).add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity()) + { + return this; + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return this; + } + + return twiceJacobianModified(false).add(this); + } + + protected ECFieldElement two(ECFieldElement x) + { + return x.add(x); + } + + protected ECFieldElement three(ECFieldElement x) + { + return two(x).add(x); + } + + // D.3.2 pg 102 (see Note:) + public ECPoint subtract(ECPoint b) + { + if (b.isInfinity()) + { + return this; + } + + // Add -b + return add(b.negate()); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new Curve25519Point(this.getCurve(), this.x, this.y.negate(), this.zs, this.withCompression); + } + + protected ECFieldElement calculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared) + { + ECFieldElement a4 = this.getCurve().getA(); + if (Z.isOne()) + { + return a4; + } + + if (ZSquared == null) + { + ZSquared = Z.square(); + } + + return ZSquared.square().multiply(a4); + } + + protected ECFieldElement getJacobianModifiedW() + { + ECFieldElement W = this.zs[1]; + if (W == null) + { + // NOTE: Rarely, twicePlus will result in the need for a lazy W1 calculation here + this.zs[1] = W = calculateJacobianModifiedW(this.zs[0], null); + } + return W; + } + + protected Curve25519Point twiceJacobianModified(boolean calculateW) + { + ECFieldElement X1 = this.x, Y1 = this.y, Z1 = this.zs[0], W1 = getJacobianModifiedW(); + + ECFieldElement X1Squared = X1.square(); + ECFieldElement M = three(X1Squared).add(W1); + ECFieldElement _2Y1 = two(Y1); + ECFieldElement _2Y1Squared = _2Y1.multiply(Y1); + ECFieldElement S = two(X1.multiply(_2Y1Squared)); + ECFieldElement X3 = M.square().subtract(two(S)); + ECFieldElement _4T = _2Y1Squared.square(); + ECFieldElement _8T = two(_4T); + ECFieldElement Y3 = M.multiply(S.subtract(X3)).subtract(_8T); + ECFieldElement W3 = calculateW ? two(_8T.multiply(W1)) : null; + ECFieldElement Z3 = Z1.isOne() ? _2Y1 : _2Y1.multiply(Z1); + + return new Curve25519Point(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }, this.withCompression); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat192.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat192.java index 6351a64c..c622350a 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat192.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat192.java @@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; import org.bouncycastle.crypto.util.Pack; +import org.bouncycastle.math.ec.Nat; public abstract class Nat192 { @@ -56,64 +57,92 @@ public abstract class Nat192 return (int)c; } - // TODO Re-write to allow full range for x? - public static int addDWord(long x, int[] z, int zOff) + public static int addTo(int[] x, int[] z) { - // assert zOff <= 4; - long c = x; - c += (z[zOff + 0] & M); - z[zOff + 0] = (int)c; + long c = 0; + c += (x[0] & M) + (z[0] & M); + z[0] = (int)c; c >>>= 32; - c += (z[zOff + 1] & M); - z[zOff + 1] = (int)c; + c += (x[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (z[5] & M); + z[5] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(z, zOff + 2); + return (int)c; } - public static int addExt(int[] xx, int[] yy, int[] zz) + public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn) { - long c = 0; - for (int i = 0; i < 12; ++i) - { - c += (xx[i] & M) + (yy[i] & M); - zz[i] = (int)c; - c >>>= 32; - } + long c = cIn & M; + c += (x[xOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; return (int)c; } - public static int addToExt(int[] x, int xOff, int[] zz, int zzOff) + public static int addToEachOther(int[] u, int uOff, int[] v, int vOff) { - // assert zzOff <= 6; long c = 0; - c += (x[xOff + 0] & M) + (zz[zzOff + 0] & M); - zz[zzOff + 0] = (int)c; + c += (u[uOff + 0] & M) + (v[vOff + 0] & M); + u[uOff + 0] = (int)c; + v[vOff + 0] = (int)c; c >>>= 32; - c += (x[xOff + 1] & M) + (zz[zzOff + 1] & M); - zz[zzOff + 1] = (int)c; + c += (u[uOff + 1] & M) + (v[vOff + 1] & M); + u[uOff + 1] = (int)c; + v[vOff + 1] = (int)c; c >>>= 32; - c += (x[xOff + 2] & M) + (zz[zzOff + 2] & M); - zz[zzOff + 2] = (int)c; + c += (u[uOff + 2] & M) + (v[vOff + 2] & M); + u[uOff + 2] = (int)c; + v[vOff + 2] = (int)c; c >>>= 32; - c += (x[xOff + 3] & M) + (zz[zzOff + 3] & M); - zz[zzOff + 3] = (int)c; + c += (u[uOff + 3] & M) + (v[vOff + 3] & M); + u[uOff + 3] = (int)c; + v[vOff + 3] = (int)c; c >>>= 32; - c += (x[xOff + 4] & M) + (zz[zzOff + 4] & M); - zz[zzOff + 4] = (int)c; + c += (u[uOff + 4] & M) + (v[vOff + 4] & M); + u[uOff + 4] = (int)c; + v[vOff + 4] = (int)c; c >>>= 32; - c += (x[xOff + 5] & M) + (zz[zzOff + 5] & M); - zz[zzOff + 5] = (int)c; + c += (u[uOff + 5] & M) + (v[vOff + 5] & M); + u[uOff + 5] = (int)c; + v[vOff + 5] = (int)c; c >>>= 32; return (int)c; } - public static int addWordExt(int x, int[] zz, int zzOff) + public static void copy(int[] x, int[] z) { - // assert zzOff <= 11; - long c = (x & M) + (zz[zzOff + 0] & M); - zz[zzOff + 0] = (int)c; - c >>>= 32; - return c == 0 ? 0 : incExt(zz, zzOff + 1); + z[0] = x[0]; + z[1] = x[1]; + z[2] = x[2]; + z[3] = x[3]; + z[4] = x[4]; + z[5] = x[5]; } public static int[] create() @@ -126,17 +155,30 @@ public abstract class Nat192 return new int[12]; } - public static int dec(int[] z, int zOff) + public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) { - // assert zOff <= 6; - for (int i = zOff; i < 6; ++i) + boolean pos = gte(x, xOff, y, yOff); + if (pos) + { + sub(x, xOff, y, yOff, z, zOff); + } + else { - if (--z[i] != -1) + sub(y, yOff, x, xOff, z, zOff); + } + return pos; + } + + public static boolean eq(int[] x, int[] y) + { + for (int i = 5; i >= 0; --i) + { + if (x[i] != y[i]) { - return 0; + return false; } } - return -1; + return true; } public static int[] fromBigInteger(BigInteger x) @@ -185,46 +227,20 @@ public abstract class Nat192 return true; } - public static boolean gteExt(int[] xx, int[] yy) + public static boolean gte(int[] x, int xOff, int[] y, int yOff) { - for (int i = 11; i >= 0; --i) + for (int i = 5; i >= 0; --i) { - int xx_i = xx[i] ^ Integer.MIN_VALUE; - int yy_i = yy[i] ^ Integer.MIN_VALUE; - if (xx_i < yy_i) + int x_i = x[xOff + i] ^ Integer.MIN_VALUE; + int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + if (x_i < y_i) return false; - if (xx_i > yy_i) + if (x_i > y_i) return true; } return true; } - public static int inc(int[] z, int zOff) - { - // assert zOff <= 6; - for (int i = zOff; i < 6; ++i) - { - if (++z[i] != 0) - { - return 0; - } - } - return 1; - } - - public static int incExt(int[] zz, int zzOff) - { - // assert zzOff <= 12; - for (int i = zzOff; i < 12; ++i) - { - if (++zz[i] != 0) - { - return 0; - } - } - return 1; - } - public static boolean isOne(int[] x) { if (x[0] != 1) @@ -253,18 +269,6 @@ public abstract class Nat192 return true; } - public static boolean isZeroExt(int[] xx) - { - for (int i = 0; i < 12; ++i) - { - if (xx[i] != 0) - { - return false; - } - } - return true; - } - public static void mul(int[] x, int[] y, int[] zz) { long y_0 = y[0] & M; @@ -322,39 +326,171 @@ public abstract class Nat192 } } - public static long mul33AddExt(int w, int[] xx, int xxOff, int[] yy, int yyOff, int[] zz, int zzOff) + public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) { - // assert x >>> 31 == 0; - // assert xxOff <= 6; - // assert yyOff <= 6; - // assert zzOff <= 6; + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + + { + long c = 0, x_0 = x[xOff + 0] & M; + c += x_0 * y_0; + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_0 * y_1; + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_0 * y_2; + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_0 * y_3; + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_0 * y_4; + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_0 * y_5; + zz[zzOff + 5] = (int)c; + c >>>= 32; + zz[zzOff + 6] = (int)c; + } + + for (int i = 1; i < 6; ++i) + { + ++zzOff; + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + zz[zzOff + 6] = (int)c; + } + } + + public static int mulAddTo(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + + long zc = 0; + for (int i = 0; i < 6; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + c += zc + (zz[i + 6] & M); + zz[i + 6] = (int)c; + zc = c >>> 32; + } + return (int)zc; + } + + public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + + long zc = 0; + for (int i = 0; i < 6; ++i) + { + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += zc + (zz[zzOff + 6] & M); + zz[zzOff + 6] = (int)c; + zc = c >>> 32; + ++zzOff; + } + return (int)zc; + } + + public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + // assert w >>> 31 == 0; long c = 0, wVal = w & M; - long xx00 = xx[xxOff + 0] & M; - c += wVal * xx00 + (yy[yyOff + 0] & M); - zz[zzOff + 0] = (int)c; + long x0 = x[xOff + 0] & M; + c += wVal * x0 + (y[yOff + 0] & M); + z[zOff + 0] = (int)c; c >>>= 32; - long xx01 = xx[xxOff + 1] & M; - c += wVal * xx01 + xx00 + (yy[yyOff + 1] & M); - zz[zzOff + 1] = (int)c; + long x1 = x[xOff + 1] & M; + c += wVal * x1 + x0 + (y[yOff + 1] & M); + z[zOff + 1] = (int)c; c >>>= 32; - long xx02 = xx[xxOff + 2] & M; - c += wVal * xx02 + xx01 + (yy[yyOff + 2] & M); - zz[zzOff + 2] = (int)c; + long x2 = x[xOff + 2] & M; + c += wVal * x2 + x1 + (y[yOff + 2] & M); + z[zOff + 2] = (int)c; c >>>= 32; - long xx03 = xx[xxOff + 3] & M; - c += wVal * xx03 + xx02 + (yy[yyOff + 3] & M); - zz[zzOff + 3] = (int)c; + long x3 = x[xOff + 3] & M; + c += wVal * x3 + x2 + (y[yOff + 3] & M); + z[zOff + 3] = (int)c; c >>>= 32; - long xx04 = xx[xxOff + 4] & M; - c += wVal * xx04 + xx03 + (yy[yyOff + 4] & M); - zz[zzOff + 4] = (int)c; + long x4 = x[xOff + 4] & M; + c += wVal * x4 + x3 + (y[yOff + 4] & M); + z[zOff + 4] = (int)c; c >>>= 32; - long xx05 = xx[xxOff + 5] & M; - c += wVal * xx05 + xx04 + (yy[yyOff + 5] & M); - zz[zzOff + 5] = (int)c; + long x5 = x[xOff + 5] & M; + c += wVal * x5 + x4 + (y[yOff + 5] & M); + z[zOff + 5] = (int)c; c >>>= 32; - c += xx05; + c += x5; return c; } @@ -404,7 +540,25 @@ public abstract class Nat192 c += (z[zOff + 3] & M); z[zOff + 3] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(z, zOff + 4); + return c == 0 ? 0 : Nat.incAt(6, z, zOff, 4); + } + + public static int mul33WordAdd(int x, int y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 3; + + long c = 0, xVal = x & M, yVal = y & M; + c += yVal * xVal + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += yVal + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(6, z, zOff, 3); } public static int mulWordDwordAdd(int x, long y, int[] z, int zOff) @@ -420,102 +574,31 @@ public abstract class Nat192 c += (z[zOff + 2] & M); z[zOff + 2] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(z, zOff + 3); + return c == 0 ? 0 : Nat.incAt(6, z, zOff, 3); } - public static int mulWordExt(int x, int[] y, int[] zz, int zzOff) + public static int mulWord(int x, int[] y, int[] z, int zOff) { - // assert zzOff <= 6; long c = 0, xVal = x & M; int i = 0; do { c += xVal * (y[i] & M); - zz[zzOff + i] = (int)c; + z[zOff + i] = (int)c; c >>>= 32; } while (++i < 6); return (int)c; } - public static int shiftDownBit(int[] x, int xLen, int c) - { - int i = xLen; - while (--i >= 0) - { - int next = x[i]; - x[i] = (next >>> 1) | (c << 31); - c = next; - } - return c << 31; - } - - public static int shiftDownBit(int[] x, int c, int[] z) - { - int i = 6; - while (--i >= 0) - { - int next = x[i]; - z[i] = (next >>> 1) | (c << 31); - c = next; - } - return c << 31; - } - - public static int shiftDownBits(int[] x, int xLen, int bits, int c) - { -// assert bits > 0 && bits < 32; - int i = xLen; - while (--i >= 0) - { - int next = x[i]; - x[i] = (next >>> bits) | (c << -bits); - c = next; - } - return c << -bits; - } - - public static int shiftDownWord(int[] x, int xLen, int c) - { - int i = xLen; - while (--i >= 0) - { - int next = x[i]; - x[i] = c; - c = next; - } - return c; - } - - public static int shiftUpBit(int[] x, int xLen, int c) - { - for (int i = 0; i < xLen; ++i) - { - int next = x[i]; - x[i] = (next << 1) | (c >>> 31); - c = next; - } - return c >>> 31; - } - - public static int shiftUpBit(int[] x, int c, int[] z) - { - for (int i = 0; i < 6; ++i) - { - int next = x[i]; - z[i] = (next << 1) | (c >>> 31); - c = next; - } - return c >>> 31; - } - public static void square(int[] x, int[] zz) { long x_0 = x[0] & M; long zz_1; + int c = 0, w; { - int c = 0, i = 5, j = 12; + int i = 5, j = 12; do { long xVal = (x[i--] & M); @@ -529,7 +612,8 @@ public abstract class Nat192 { long p = x_0 * x_0; zz_1 = ((c << 31) & M) | (p >>> 33); - zz[0] = (int)(p >>> 1); + zz[0] = (int)p; + c = (int)(p >>> 32) & 1; } } @@ -538,7 +622,9 @@ public abstract class Nat192 { zz_1 += x_1 * x_0; - zz[1] = (int)zz_1; + w = (int)zz_1; + zz[1] = (w << 1) | c; + c = w >>> 31; zz_2 += zz_1 >>> 32; } @@ -547,7 +633,9 @@ public abstract class Nat192 long zz_4 = zz[4] & M; { zz_2 += x_2 * x_0; - zz[2] = (int)zz_2; + w = (int)zz_2; + zz[2] = (w << 1) | c; + c = w >>> 31; zz_3 += (zz_2 >>> 32) + x_2 * x_1; zz_4 += zz_3 >>> 32; zz_3 &= M; @@ -558,7 +646,9 @@ public abstract class Nat192 long zz_6 = zz[6] & M; { zz_3 += x_3 * x_0; - zz[3] = (int)zz_3; + w = (int)zz_3; + zz[3] = (w << 1) | c; + c = w >>> 31; zz_4 += (zz_3 >>> 32) + x_3 * x_1; zz_5 += (zz_4 >>> 32) + x_3 * x_2; zz_4 &= M; @@ -571,7 +661,9 @@ public abstract class Nat192 long zz_8 = zz[8] & M; { zz_4 += x_4 * x_0; - zz[4] = (int)zz_4; + w = (int)zz_4; + zz[4] = (w << 1) | c; + c = w >>> 31; zz_5 += (zz_4 >>> 32) + x_4 * x_1; zz_6 += (zz_5 >>> 32) + x_4 * x_2; zz_5 &= M; @@ -586,7 +678,9 @@ public abstract class Nat192 long zz_10 = zz[10] & M; { zz_5 += x_5 * x_0; - zz[5] = (int)zz_5; + w = (int)zz_5; + zz[5] = (w << 1) | c; + c = w >>> 31; zz_6 += (zz_5 >>> 32) + x_5 * x_1; zz_7 += (zz_6 >>> 32) + x_5 * x_2; zz_8 += (zz_7 >>> 32) + x_5 * x_3; @@ -594,29 +688,139 @@ public abstract class Nat192 zz_10 += zz_9 >>> 32; } - zz[6] = (int)zz_6; - zz[7] = (int)zz_7; - zz[8] = (int)zz_8; - zz[9] = (int)zz_9; - zz[10] = (int)zz_10; - zz[11] += (int)(zz_10 >>> 32); + w = (int)zz_6; + zz[6] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_7; + zz[7] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_8; + zz[8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[10] = (w << 1) | c; + c = w >>> 31; + w = zz[11] + (int)(zz_10 >> 32); + zz[11] = (w << 1) | c; + } + + public static void square(int[] x, int xOff, int[] zz, int zzOff) + { + long x_0 = x[xOff + 0] & M; + long zz_1; - shiftUpBit(zz, 12, (int)x_0 << 31); - } + int c = 0, w; + { + int i = 5, j = 12; + do + { + long xVal = (x[xOff + i--] & M); + long p = xVal * xVal; + zz[zzOff + --j] = (c << 31) | (int)(p >>> 33); + zz[zzOff + --j] = (int)(p >>> 1); + c = (int)p; + } + while (i > 0); + + { + long p = x_0 * x_0; + zz_1 = ((c << 31) & M) | (p >>> 33); + zz[zzOff + 0] = (int)p; + c = (int)(p >>> 32) & 1; + } + } + + long x_1 = x[xOff + 1] & M; + long zz_2 = zz[zzOff + 2] & M; - public static int squareWordAddExt(int[] x, int xPos, int[] zz) - { - // assert xPos > 0 && xPos < 6; - long c = 0, xVal = x[xPos] & M; - int i = 0; - do { - c += xVal * (x[i] & M) + (zz[xPos + i] & M); - zz[xPos + i] = (int)c; - c >>>= 32; + zz_1 += x_1 * x_0; + w = (int)zz_1; + zz[zzOff + 1] = (w << 1) | c; + c = w >>> 31; + zz_2 += zz_1 >>> 32; } - while (++i < xPos); - return (int)c; + + long x_2 = x[xOff + 2] & M; + long zz_3 = zz[zzOff + 3] & M; + long zz_4 = zz[zzOff + 4] & M; + { + zz_2 += x_2 * x_0; + w = (int)zz_2; + zz[zzOff + 2] = (w << 1) | c; + c = w >>> 31; + zz_3 += (zz_2 >>> 32) + x_2 * x_1; + zz_4 += zz_3 >>> 32; + zz_3 &= M; + } + + long x_3 = x[xOff + 3] & M; + long zz_5 = zz[zzOff + 5] & M; + long zz_6 = zz[zzOff + 6] & M; + { + zz_3 += x_3 * x_0; + w = (int)zz_3; + zz[zzOff + 3] = (w << 1) | c; + c = w >>> 31; + zz_4 += (zz_3 >>> 32) + x_3 * x_1; + zz_5 += (zz_4 >>> 32) + x_3 * x_2; + zz_4 &= M; + zz_6 += zz_5 >>> 32; + zz_5 &= M; + } + + long x_4 = x[xOff + 4] & M; + long zz_7 = zz[zzOff + 7] & M; + long zz_8 = zz[zzOff + 8] & M; + { + zz_4 += x_4 * x_0; + w = (int)zz_4; + zz[zzOff + 4] = (w << 1) | c; + c = w >>> 31; + zz_5 += (zz_4 >>> 32) + x_4 * x_1; + zz_6 += (zz_5 >>> 32) + x_4 * x_2; + zz_5 &= M; + zz_7 += (zz_6 >>> 32) + x_4 * x_3; + zz_6 &= M; + zz_8 += zz_7 >>> 32; + zz_7 &= M; + } + + long x_5 = x[xOff + 5] & M; + long zz_9 = zz[zzOff + 9] & M; + long zz_10 = zz[zzOff + 10] & M; + { + zz_5 += x_5 * x_0; + w = (int)zz_5; + zz[zzOff + 5] = (w << 1) | c; + c = w >>> 31; + zz_6 += (zz_5 >>> 32) + x_5 * x_1; + zz_7 += (zz_6 >>> 32) + x_5 * x_2; + zz_8 += (zz_7 >>> 32) + x_5 * x_3; + zz_9 += (zz_8 >>> 32) + x_5 * x_4; + zz_10 += zz_9 >>> 32; + } + + w = (int)zz_6; + zz[zzOff + 6] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_7; + zz[zzOff + 7] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_8; + zz[zzOff + 8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[zzOff + 9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[zzOff + 10] = (w << 1) | c; + c = w >>> 31; + w = zz[zzOff + 11] + (int)(zz_10 >> 32); + zz[zzOff + 11] = (w << 1) | c; } public static int sub(int[] x, int[] y, int[] z) @@ -643,6 +847,30 @@ public abstract class Nat192 return (int)c; } + public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) - (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (x[xOff + 1] & M) - (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>= 32; + c += (x[xOff + 2] & M) - (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>= 32; + c += (x[xOff + 3] & M) - (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>= 32; + c += (x[xOff + 4] & M) - (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>= 32; + c += (x[xOff + 5] & M) - (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>= 32; + return (int)c; + } + public static int subBothFrom(int[] x, int[] y, int[] z) { long c = 0; @@ -667,52 +895,50 @@ public abstract class Nat192 return (int)c; } - // TODO Re-write to allow full range for x? - public static int subDWord(long x, int[] z) + public static int subFrom(int[] x, int[] z) { - long c = -x; - c += (z[0] & M); + long c = 0; + c += (z[0] & M) - (x[0] & M); z[0] = (int)c; c >>= 32; - c += (z[1] & M); + c += (z[1] & M) - (x[1] & M); z[1] = (int)c; c >>= 32; - return c == 0 ? 0 : dec(z, 2); - } - - public static int subExt(int[] xx, int[] yy, int[] zz) - { - long c = 0; - for (int i = 0; i < 12; ++i) - { - c += (xx[i] & M) - (yy[i] & M); - zz[i] = (int)c; - c >>= 32; - } + c += (z[2] & M) - (x[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M); + z[5] = (int)c; + c >>= 32; return (int)c; } - public static int subFromExt(int[] x, int xOff, int[] zz, int zzOff) + public static int subFrom(int[] x, int xOff, int[] z, int zOff) { - // assert zzOff <= 6; long c = 0; - c += (zz[zzOff + 0] & M) - (x[xOff + 0] & M); - zz[zzOff + 0] = (int)c; + c += (z[zOff + 0] & M) - (x[xOff + 0] & M); + z[zOff + 0] = (int)c; c >>= 32; - c += (zz[zzOff + 1] & M) - (x[xOff + 1] & M); - zz[zzOff + 1] = (int)c; + c += (z[zOff + 1] & M) - (x[xOff + 1] & M); + z[zOff + 1] = (int)c; c >>= 32; - c += (zz[zzOff + 2] & M) - (x[xOff + 2] & M); - zz[zzOff + 2] = (int)c; + c += (z[zOff + 2] & M) - (x[xOff + 2] & M); + z[zOff + 2] = (int)c; c >>= 32; - c += (zz[zzOff + 3] & M) - (x[xOff + 3] & M); - zz[zzOff + 3] = (int)c; + c += (z[zOff + 3] & M) - (x[xOff + 3] & M); + z[zOff + 3] = (int)c; c >>= 32; - c += (zz[zzOff + 4] & M) - (x[xOff + 4] & M); - zz[zzOff + 4] = (int)c; + c += (z[zOff + 4] & M) - (x[xOff + 4] & M); + z[zOff + 4] = (int)c; c >>= 32; - c += (zz[zzOff + 5] & M) - (x[xOff + 5] & M); - zz[zzOff + 5] = (int)c; + c += (z[zOff + 5] & M) - (x[xOff + 5] & M); + z[zOff + 5] = (int)c; c >>= 32; return (int)c; } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat224.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat224.java new file mode 100644 index 00000000..8f1a66dc --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat224.java @@ -0,0 +1,1183 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.crypto.util.Pack; +import org.bouncycastle.math.ec.Nat; + +public abstract class Nat224 +{ + private static final long M = 0xFFFFFFFFL; + + public static int add(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) + (y[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (y[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (y[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (y[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (y[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (y[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (y[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int add(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) + (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += (x[xOff + 6] & M) + (y[yOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addBothTo(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) + (y[0] & M) + (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (y[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (y[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (y[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (y[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (y[5] & M) + (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (y[6] & M) + (z[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addBothTo(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) + (y[yOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (y[yOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (y[yOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (y[yOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (y[yOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (y[yOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += (x[xOff + 6] & M) + (y[yOff + 6] & M) + (z[zOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addTo(int[] x, int[] z) + { + long c = 0; + c += (x[0] & M) + (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += (x[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (z[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addTo(int[] x, int xOff, int[] z, int zOff, int cIn) + { + long c = cIn & M; + c += (x[xOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += (x[xOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (x[xOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (x[xOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += (x[xOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += (x[xOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += (x[xOff + 6] & M) + (z[zOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int addToEachOther(int[] u, int uOff, int[] v, int vOff) + { + long c = 0; + c += (u[uOff + 0] & M) + (v[vOff + 0] & M); + u[uOff + 0] = (int)c; + v[vOff + 0] = (int)c; + c >>>= 32; + c += (u[uOff + 1] & M) + (v[vOff + 1] & M); + u[uOff + 1] = (int)c; + v[vOff + 1] = (int)c; + c >>>= 32; + c += (u[uOff + 2] & M) + (v[vOff + 2] & M); + u[uOff + 2] = (int)c; + v[vOff + 2] = (int)c; + c >>>= 32; + c += (u[uOff + 3] & M) + (v[vOff + 3] & M); + u[uOff + 3] = (int)c; + v[vOff + 3] = (int)c; + c >>>= 32; + c += (u[uOff + 4] & M) + (v[vOff + 4] & M); + u[uOff + 4] = (int)c; + v[vOff + 4] = (int)c; + c >>>= 32; + c += (u[uOff + 5] & M) + (v[vOff + 5] & M); + u[uOff + 5] = (int)c; + v[vOff + 5] = (int)c; + c >>>= 32; + c += (u[uOff + 6] & M) + (v[vOff + 6] & M); + u[uOff + 6] = (int)c; + v[vOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static void copy(int[] x, int[] z) + { + z[0] = x[0]; + z[1] = x[1]; + z[2] = x[2]; + z[3] = x[3]; + z[4] = x[4]; + z[5] = x[5]; + z[6] = x[6]; + } + + public static int[] create() + { + return new int[7]; + } + + public static int[] createExt() + { + return new int[14]; + } + + public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + boolean pos = gte(x, xOff, y, yOff); + if (pos) + { + sub(x, xOff, y, yOff, z, zOff); + } + else + { + sub(y, yOff, x, xOff, z, zOff); + } + return pos; + } + + public static boolean eq(int[] x, int[] y) + { + for (int i = 6; i >= 0; --i) + { + if (x[i] != y[i]) + { + return false; + } + } + return true; + } + + public static int[] fromBigInteger(BigInteger x) + { + if (x.signum() < 0 || x.bitLength() > 224) + { + throw new IllegalArgumentException(); + } + + int[] z = create(); + int i = 0; + while (x.signum() != 0) + { + z[i++] = x.intValue(); + x = x.shiftRight(32); + } + return z; + } + + public static int getBit(int[] x, int bit) + { + if (bit == 0) + { + return x[0] & 1; + } + int w = bit >> 5; + if (w < 0 || w >= 7) + { + return 0; + } + int b = bit & 31; + return (x[w] >>> b) & 1; + } + + public static boolean gte(int[] x, int[] y) + { + for (int i = 6; i >= 0; --i) + { + int x_i = x[i] ^ Integer.MIN_VALUE; + int y_i = y[i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static boolean gte(int[] x, int xOff, int[] y, int yOff) + { + for (int i = 6; i >= 0; --i) + { + int x_i = x[xOff + i] ^ Integer.MIN_VALUE; + int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + + public static boolean isOne(int[] x) + { + if (x[0] != 1) + { + return false; + } + for (int i = 1; i < 7; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static boolean isZero(int[] x) + { + for (int i = 0; i < 7; ++i) + { + if (x[i] != 0) + { + return false; + } + } + return true; + } + + public static void mul(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + long y_6 = y[6] & M; + + { + long c = 0, x_0 = x[0] & M; + c += x_0 * y_0; + zz[0] = (int)c; + c >>>= 32; + c += x_0 * y_1; + zz[1] = (int)c; + c >>>= 32; + c += x_0 * y_2; + zz[2] = (int)c; + c >>>= 32; + c += x_0 * y_3; + zz[3] = (int)c; + c >>>= 32; + c += x_0 * y_4; + zz[4] = (int)c; + c >>>= 32; + c += x_0 * y_5; + zz[5] = (int)c; + c >>>= 32; + c += x_0 * y_6; + zz[6] = (int)c; + c >>>= 32; + zz[7] = (int)c; + } + + for (int i = 1; i < 7; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[i + 6] & M); + zz[i + 6] = (int)c; + c >>>= 32; + zz[i + 7] = (int)c; + } + } + + public static void mul(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + long y_6 = y[yOff + 6] & M; + + { + long c = 0, x_0 = x[xOff + 0] & M; + c += x_0 * y_0; + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_0 * y_1; + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_0 * y_2; + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_0 * y_3; + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_0 * y_4; + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_0 * y_5; + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += x_0 * y_6; + zz[zzOff + 6] = (int)c; + c >>>= 32; + zz[zzOff + 7] = (int)c; + } + + for (int i = 1; i < 7; ++i) + { + ++zzOff; + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[zzOff + 6] & M); + zz[zzOff + 6] = (int)c; + c >>>= 32; + zz[zzOff + 7] = (int)c; + } + } + + public static int mulAddTo(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + long y_6 = y[6] & M; + + long zc = 0; + for (int i = 0; i < 7; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[i + 6] & M); + zz[i + 6] = (int)c; + c >>>= 32; + c += zc + (zz[i + 7] & M); + zz[i + 7] = (int)c; + zc = c >>> 32; + } + return (int)zc; + } + + public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + { + long y_0 = y[yOff + 0] & M; + long y_1 = y[yOff + 1] & M; + long y_2 = y[yOff + 2] & M; + long y_3 = y[yOff + 3] & M; + long y_4 = y[yOff + 4] & M; + long y_5 = y[yOff + 5] & M; + long y_6 = y[yOff + 6] & M; + + long zc = 0; + for (int i = 0; i < 7; ++i) + { + long c = 0, x_i = x[xOff + i] & M; + c += x_i * y_0 + (zz[zzOff + 0] & M); + zz[zzOff + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[zzOff + 1] & M); + zz[zzOff + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[zzOff + 2] & M); + zz[zzOff + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[zzOff + 3] & M); + zz[zzOff + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[zzOff + 6] & M); + zz[zzOff + 6] = (int)c; + c >>>= 32; + c += zc + (zz[zzOff + 7] & M); + zz[zzOff + 7] = (int)c; + zc = c >>> 32; + ++zzOff; + } + return (int)zc; + } + + public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + // assert w >>> 31 == 0; + + long c = 0, wVal = w & M; + long x0 = x[xOff + 0] & M; + c += wVal * x0 + (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + long x1 = x[xOff + 1] & M; + c += wVal * x1 + x0 + (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + long x2 = x[xOff + 2] & M; + c += wVal * x2 + x1 + (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + long x3 = x[xOff + 3] & M; + c += wVal * x3 + x2 + (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + long x4 = x[xOff + 4] & M; + c += wVal * x4 + x3 + (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + long x5 = x[xOff + 5] & M; + c += wVal * x5 + x4 + (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + long x6 = x[xOff + 6] & M; + c += wVal * x6 + x5 + (y[yOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + c += x6; + return c; + } + + public static int mulByWord(int x, int[] z) + { + long c = 0, xVal = x & M; + c += xVal * (z[0] & M); + z[0] = (int)c; + c >>>= 32; + c += xVal * (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += xVal * (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += xVal * (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += xVal * (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += xVal * (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += xVal * (z[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mulByWordAddTo(int x, int[] y, int[] z) + { + long c = 0, xVal = x & M; + c += xVal * (z[0] & M) + (y[0] & M); + z[0] = (int)c; + c >>>= 32; + c += xVal * (z[1] & M) + (y[1] & M); + z[1] = (int)c; + c >>>= 32; + c += xVal * (z[2] & M) + (y[2] & M); + z[2] = (int)c; + c >>>= 32; + c += xVal * (z[3] & M) + (y[3] & M); + z[3] = (int)c; + c >>>= 32; + c += xVal * (z[4] & M) + (y[4] & M); + z[4] = (int)c; + c >>>= 32; + c += xVal * (z[5] & M) + (y[5] & M); + z[5] = (int)c; + c >>>= 32; + c += xVal * (z[6] & M) + (y[6] & M); + z[6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mulWordAddTo(int x, int[] y, int yOff, int[] z, int zOff) + { + long c = 0, xVal = x & M; + c += xVal * (y[yOff + 0] & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 1] & M) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 2] & M) + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 3] & M) + (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 4] & M) + (z[zOff + 4] & M); + z[zOff + 4] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 5] & M) + (z[zOff + 5] & M); + z[zOff + 5] = (int)c; + c >>>= 32; + c += xVal * (y[yOff + 6] & M) + (z[zOff + 6] & M); + z[zOff + 6] = (int)c; + c >>>= 32; + return (int)c; + } + + public static int mul33DWordAdd(int x, long y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 3; + + long c = 0, xVal = x & M; + long y00 = y & M; + c += xVal * y00 + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + long y01 = y >>> 32; + c += xVal * y01 + y00 + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += y01 + (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + c += (z[zOff + 3] & M); + z[zOff + 3] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(7, z, zOff, 4); + } + + public static int mul33WordAdd(int x, int y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 4; + + long c = 0, xVal = x & M, yVal = y & M; + c += yVal * xVal + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += yVal + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(7, z, zOff, 3); + } + + public static int mulWordDwordAdd(int x, long y, int[] z, int zOff) + { + // assert zOff <= 4; + long c = 0, xVal = x & M; + c += xVal * (y & M) + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += xVal * (y >>> 32) + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(7, z, zOff, 3); + } + + public static int mulWord(int x, int[] y, int[] z, int zOff) + { + long c = 0, xVal = x & M; + int i = 0; + do + { + c += xVal * (y[i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + while (++i < 7); + return (int)c; + } + + public static void square(int[] x, int[] zz) + { + long x_0 = x[0] & M; + long zz_1; + + int c = 0, w; + { + int i = 6, j = 14; + do + { + long xVal = (x[i--] & M); + long p = xVal * xVal; + zz[--j] = (c << 31) | (int)(p >>> 33); + zz[--j] = (int)(p >>> 1); + c = (int)p; + } + while (i > 0); + + { + long p = x_0 * x_0; + zz_1 = ((c << 31) & M) | (p >>> 33); + zz[0] = (int)p; + c = (int)(p >>> 32) & 1; + } + } + + long x_1 = x[1] & M; + long zz_2 = zz[2] & M; + + { + zz_1 += x_1 * x_0; + w = (int)zz_1; + zz[1] = (w << 1) | c; + c = w >>> 31; + zz_2 += zz_1 >>> 32; + } + + long x_2 = x[2] & M; + long zz_3 = zz[3] & M; + long zz_4 = zz[4] & M; + { + zz_2 += x_2 * x_0; + w = (int)zz_2; + zz[2] = (w << 1) | c; + c = w >>> 31; + zz_3 += (zz_2 >>> 32) + x_2 * x_1; + zz_4 += zz_3 >>> 32; + zz_3 &= M; + } + + long x_3 = x[3] & M; + long zz_5 = zz[5] & M; + long zz_6 = zz[6] & M; + { + zz_3 += x_3 * x_0; + w = (int)zz_3; + zz[3] = (w << 1) | c; + c = w >>> 31; + zz_4 += (zz_3 >>> 32) + x_3 * x_1; + zz_5 += (zz_4 >>> 32) + x_3 * x_2; + zz_4 &= M; + zz_6 += zz_5 >>> 32; + zz_5 &= M; + } + + long x_4 = x[4] & M; + long zz_7 = zz[7] & M; + long zz_8 = zz[8] & M; + { + zz_4 += x_4 * x_0; + w = (int)zz_4; + zz[4] = (w << 1) | c; + c = w >>> 31; + zz_5 += (zz_4 >>> 32) + x_4 * x_1; + zz_6 += (zz_5 >>> 32) + x_4 * x_2; + zz_5 &= M; + zz_7 += (zz_6 >>> 32) + x_4 * x_3; + zz_6 &= M; + zz_8 += zz_7 >>> 32; + zz_7 &= M; + } + + long x_5 = x[5] & M; + long zz_9 = zz[9] & M; + long zz_10 = zz[10] & M; + { + zz_5 += x_5 * x_0; + w = (int)zz_5; + zz[5] = (w << 1) | c; + c = w >>> 31; + zz_6 += (zz_5 >>> 32) + x_5 * x_1; + zz_7 += (zz_6 >>> 32) + x_5 * x_2; + zz_6 &= M; + zz_8 += (zz_7 >>> 32) + x_5 * x_3; + zz_7 &= M; + zz_9 += (zz_8 >>> 32) + x_5 * x_4; + zz_8 &= M; + zz_10 += zz_9 >>> 32; + zz_9 &= M; + } + + long x_6 = x[6] & M; + long zz_11 = zz[11] & M; + long zz_12 = zz[12] & M; + { + zz_6 += x_6 * x_0; + w = (int)zz_6; + zz[6] = (w << 1) | c; + c = w >>> 31; + zz_7 += (zz_6 >>> 32) + x_6 * x_1; + zz_8 += (zz_7 >>> 32) + x_6 * x_2; + zz_9 += (zz_8 >>> 32) + x_6 * x_3; + zz_10 += (zz_9 >>> 32) + x_6 * x_4; + zz_11 += (zz_10 >>> 32) + x_6 * x_5; + zz_12 += zz_11 >>> 32; + } + + w = (int)zz_7; + zz[7] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_8; + zz[8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[10] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_11; + zz[11] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_12; + zz[12] = (w << 1) | c; + c = w >>> 31; + w = zz[13] + (int)(zz_12 >> 32); + zz[13] = (w << 1) | c; + } + + public static void square(int[] x, int xOff, int[] zz, int zzOff) + { + long x_0 = x[xOff + 0] & M; + long zz_1; + + int c = 0, w; + { + int i = 6, j = 14; + do + { + long xVal = (x[xOff + i--] & M); + long p = xVal * xVal; + zz[zzOff + --j] = (c << 31) | (int)(p >>> 33); + zz[zzOff + --j] = (int)(p >>> 1); + c = (int)p; + } + while (i > 0); + + { + long p = x_0 * x_0; + zz_1 = ((c << 31) & M) | (p >>> 33); + zz[zzOff + 0] = (int)p; + c = (int)(p >>> 32) & 1; + } + } + + long x_1 = x[xOff + 1] & M; + long zz_2 = zz[zzOff + 2] & M; + + { + zz_1 += x_1 * x_0; + w = (int)zz_1; + zz[zzOff + 1] = (w << 1) | c; + c = w >>> 31; + zz_2 += zz_1 >>> 32; + } + + long x_2 = x[xOff + 2] & M; + long zz_3 = zz[zzOff + 3] & M; + long zz_4 = zz[zzOff + 4] & M; + { + zz_2 += x_2 * x_0; + w = (int)zz_2; + zz[zzOff + 2] = (w << 1) | c; + c = w >>> 31; + zz_3 += (zz_2 >>> 32) + x_2 * x_1; + zz_4 += zz_3 >>> 32; + zz_3 &= M; + } + + long x_3 = x[xOff + 3] & M; + long zz_5 = zz[zzOff + 5] & M; + long zz_6 = zz[zzOff + 6] & M; + { + zz_3 += x_3 * x_0; + w = (int)zz_3; + zz[zzOff + 3] = (w << 1) | c; + c = w >>> 31; + zz_4 += (zz_3 >>> 32) + x_3 * x_1; + zz_5 += (zz_4 >>> 32) + x_3 * x_2; + zz_4 &= M; + zz_6 += zz_5 >>> 32; + zz_5 &= M; + } + + long x_4 = x[xOff + 4] & M; + long zz_7 = zz[zzOff + 7] & M; + long zz_8 = zz[zzOff + 8] & M; + { + zz_4 += x_4 * x_0; + w = (int)zz_4; + zz[zzOff + 4] = (w << 1) | c; + c = w >>> 31; + zz_5 += (zz_4 >>> 32) + x_4 * x_1; + zz_6 += (zz_5 >>> 32) + x_4 * x_2; + zz_5 &= M; + zz_7 += (zz_6 >>> 32) + x_4 * x_3; + zz_6 &= M; + zz_8 += zz_7 >>> 32; + zz_7 &= M; + } + + long x_5 = x[xOff + 5] & M; + long zz_9 = zz[zzOff + 9] & M; + long zz_10 = zz[zzOff + 10] & M; + { + zz_5 += x_5 * x_0; + w = (int)zz_5; + zz[zzOff + 5] = (w << 1) | c; + c = w >>> 31; + zz_6 += (zz_5 >>> 32) + x_5 * x_1; + zz_7 += (zz_6 >>> 32) + x_5 * x_2; + zz_6 &= M; + zz_8 += (zz_7 >>> 32) + x_5 * x_3; + zz_7 &= M; + zz_9 += (zz_8 >>> 32) + x_5 * x_4; + zz_8 &= M; + zz_10 += zz_9 >>> 32; + zz_9 &= M; + } + + long x_6 = x[xOff + 6] & M; + long zz_11 = zz[zzOff + 11] & M; + long zz_12 = zz[zzOff + 12] & M; + { + zz_6 += x_6 * x_0; + w = (int)zz_6; + zz[zzOff + 6] = (w << 1) | c; + c = w >>> 31; + zz_7 += (zz_6 >>> 32) + x_6 * x_1; + zz_8 += (zz_7 >>> 32) + x_6 * x_2; + zz_9 += (zz_8 >>> 32) + x_6 * x_3; + zz_10 += (zz_9 >>> 32) + x_6 * x_4; + zz_11 += (zz_10 >>> 32) + x_6 * x_5; + zz_12 += zz_11 >>> 32; + } + + w = (int)zz_7; + zz[zzOff + 7] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_8; + zz[zzOff + 8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[zzOff + 9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[zzOff + 10] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_11; + zz[zzOff + 11] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_12; + zz[zzOff + 12] = (w << 1) | c; + c = w >>> 31; + w = zz[zzOff + 13] + (int)(zz_12 >> 32); + zz[zzOff + 13] = (w << 1) | c; + } + + public static int sub(int[] x, int[] y, int[] z) + { + long c = 0; + c += (x[0] & M) - (y[0] & M); + z[0] = (int)c; + c >>= 32; + c += (x[1] & M) - (y[1] & M); + z[1] = (int)c; + c >>= 32; + c += (x[2] & M) - (y[2] & M); + z[2] = (int)c; + c >>= 32; + c += (x[3] & M) - (y[3] & M); + z[3] = (int)c; + c >>= 32; + c += (x[4] & M) - (y[4] & M); + z[4] = (int)c; + c >>= 32; + c += (x[5] & M) - (y[5] & M); + z[5] = (int)c; + c >>= 32; + c += (x[6] & M) - (y[6] & M); + z[6] = (int)c; + c >>= 32; + return (int)c; + } + + public static int sub(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long c = 0; + c += (x[xOff + 0] & M) - (y[yOff + 0] & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (x[xOff + 1] & M) - (y[yOff + 1] & M); + z[zOff + 1] = (int)c; + c >>= 32; + c += (x[xOff + 2] & M) - (y[yOff + 2] & M); + z[zOff + 2] = (int)c; + c >>= 32; + c += (x[xOff + 3] & M) - (y[yOff + 3] & M); + z[zOff + 3] = (int)c; + c >>= 32; + c += (x[xOff + 4] & M) - (y[yOff + 4] & M); + z[zOff + 4] = (int)c; + c >>= 32; + c += (x[xOff + 5] & M) - (y[yOff + 5] & M); + z[zOff + 5] = (int)c; + c >>= 32; + c += (x[xOff + 6] & M) - (y[yOff + 6] & M); + z[zOff + 6] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subBothFrom(int[] x, int[] y, int[] z) + { + long c = 0; + c += (z[0] & M) - (x[0] & M) - (y[0] & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - (x[1] & M) - (y[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M) - (x[2] & M) - (y[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M) - (y[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M) - (y[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M) - (y[5] & M); + z[5] = (int)c; + c >>= 32; + c += (z[6] & M) - (x[6] & M) - (y[6] & M); + z[6] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subFrom(int[] x, int[] z) + { + long c = 0; + c += (z[0] & M) - (x[0] & M); + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - (x[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M) - (x[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M); + z[5] = (int)c; + c >>= 32; + c += (z[6] & M) - (x[6] & M); + z[6] = (int)c; + c >>= 32; + return (int)c; + } + + public static int subFrom(int[] x, int xOff, int[] z, int zOff) + { + long c = 0; + c += (z[zOff + 0] & M) - (x[xOff + 0] & M); + z[zOff + 0] = (int)c; + c >>= 32; + c += (z[zOff + 1] & M) - (x[xOff + 1] & M); + z[zOff + 1] = (int)c; + c >>= 32; + c += (z[zOff + 2] & M) - (x[xOff + 2] & M); + z[zOff + 2] = (int)c; + c >>= 32; + c += (z[zOff + 3] & M) - (x[xOff + 3] & M); + z[zOff + 3] = (int)c; + c >>= 32; + c += (z[zOff + 4] & M) - (x[xOff + 4] & M); + z[zOff + 4] = (int)c; + c >>= 32; + c += (z[zOff + 5] & M) - (x[xOff + 5] & M); + z[zOff + 5] = (int)c; + c >>= 32; + c += (z[zOff + 6] & M) - (x[xOff + 6] & M); + z[zOff + 6] = (int)c; + c >>= 32; + return (int)c; + } + + public static BigInteger toBigInteger(int[] x) + { + byte[] bs = new byte[28]; + for (int i = 0; i < 7; ++i) + { + int x_i = x[i]; + if (x_i != 0) + { + Pack.intToBigEndian(x_i, bs, (6 - i) << 2); + } + } + return new BigInteger(1, bs); + } + + public static void zero(int[] z) + { + z[0] = 0; + z[1] = 0; + z[2] = 0; + z[3] = 0; + z[4] = 0; + z[5] = 0; + z[6] = 0; + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java index 6a228fdb..6947317b 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat256.java @@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; import org.bouncycastle.crypto.util.Pack; +import org.bouncycastle.math.ec.Nat; public abstract class Nat256 { @@ -128,29 +129,33 @@ public abstract class Nat256 return (int)c; } - // TODO Re-write to allow full range for x? - public static int addDWord(long x, int[] z, int zOff) + public static int addTo(int[] x, int[] z) { - // assert zOff <= 6; - long c = x; - c += (z[zOff + 0] & M); - z[zOff + 0] = (int)c; + long c = 0; + c += (x[0] & M) + (z[0] & M); + z[0] = (int)c; c >>>= 32; - c += (z[zOff + 1] & M); - z[zOff + 1] = (int)c; + c += (x[1] & M) + (z[1] & M); + z[1] = (int)c; + c >>>= 32; + c += (x[2] & M) + (z[2] & M); + z[2] = (int)c; + c >>>= 32; + c += (x[3] & M) + (z[3] & M); + z[3] = (int)c; + c >>>= 32; + c += (x[4] & M) + (z[4] & M); + z[4] = (int)c; + c >>>= 32; + c += (x[5] & M) + (z[5] & M); + z[5] = (int)c; + c >>>= 32; + c += (x[6] & M) + (z[6] & M); + z[6] = (int)c; + c >>>= 32; + c += (x[7] & M) + (z[7] & M); + z[7] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(z, zOff + 2); - } - - public static int addExt(int[] xx, int[] yy, int[] zz) - { - long c = 0; - for (int i = 0; i < 16; ++i) - { - c += (xx[i] & M) + (yy[i] & M); - zz[i] = (int)c; - c >>>= 32; - } return (int)c; } @@ -222,24 +227,6 @@ public abstract class Nat256 return (int)c; } - public static int addWord(int x, int[] z, int zOff) - { - // assert zzOff <= 7; - long c = (x & M) + (z[zOff + 0] & M); - z[zOff + 0] = (int)c; - c >>>= 32; - return c == 0 ? 0 : inc(z, zOff + 1); - } - - public static int addWordExt(int x, int[] zz, int zzOff) - { - // assert zzOff <= 15; - long c = (x & M) + (zz[zzOff + 0] & M); - zz[zzOff + 0] = (int)c; - c >>>= 32; - return c == 0 ? 0 : incExt(zz, zzOff + 1); - } - public static void copy(int[] x, int[] z) { z[0] = x[0]; @@ -262,32 +249,6 @@ public abstract class Nat256 return new int[16]; } - public static int dec(int[] z, int zOff) - { - // assert zOff <= 8; - for (int i = zOff; i < 8; ++i) - { - if (--z[i] != -1) - { - return 0; - } - } - return -1; - } - - public static int decExt(int[] zz, int zzOff) - { - // assert zOff <= 16; - for (int i = zzOff; i < 16; ++i) - { - if (--zz[i] != -1) - { - return 0; - } - } - return -1; - } - public static boolean diff(int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) { boolean pos = gte(x, xOff, y, yOff); @@ -302,6 +263,18 @@ public abstract class Nat256 return pos; } + public static boolean eq(int[] x, int[] y) + { + for (int i = 7; i >= 0; --i) + { + if (x[i] != y[i]) + { + return false; + } + } + return true; + } + public static int[] fromBigInteger(BigInteger x) { if (x.signum() < 0 || x.bitLength() > 256) @@ -362,46 +335,6 @@ public abstract class Nat256 return true; } - public static boolean gteExt(int[] xx, int[] yy) - { - for (int i = 15; i >= 0; --i) - { - int xx_i = xx[i] ^ Integer.MIN_VALUE; - int yy_i = yy[i] ^ Integer.MIN_VALUE; - if (xx_i < yy_i) - return false; - if (xx_i > yy_i) - return true; - } - return true; - } - - public static int inc(int[] z, int zOff) - { - // assert zOff <= 8; - for (int i = zOff; i < 8; ++i) - { - if (++z[i] != 0) - { - return 0; - } - } - return 1; - } - - public static int incExt(int[] zz, int zzOff) - { - // assert zzOff <= 16; - for (int i = zzOff; i < 16; ++i) - { - if (++zz[i] != 0) - { - return 0; - } - } - return 1; - } - public static boolean isOne(int[] x) { if (x[0] != 1) @@ -430,18 +363,6 @@ public abstract class Nat256 return true; } - public static boolean isZeroExt(int[] xx) - { - for (int i = 0; i < 16; ++i) - { - if (xx[i] != 0) - { - return false; - } - } - return true; - } - public static void mul(int[] x, int[] y, int[] zz) { long y_0 = y[0] & M; @@ -585,7 +506,53 @@ public abstract class Nat256 } } - public static int mulAdd(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) + public static int mulAddTo(int[] x, int[] y, int[] zz) + { + long y_0 = y[0] & M; + long y_1 = y[1] & M; + long y_2 = y[2] & M; + long y_3 = y[3] & M; + long y_4 = y[4] & M; + long y_5 = y[5] & M; + long y_6 = y[6] & M; + long y_7 = y[7] & M; + + long zc = 0; + for (int i = 0; i < 8; ++i) + { + long c = 0, x_i = x[i] & M; + c += x_i * y_0 + (zz[i + 0] & M); + zz[i + 0] = (int)c; + c >>>= 32; + c += x_i * y_1 + (zz[i + 1] & M); + zz[i + 1] = (int)c; + c >>>= 32; + c += x_i * y_2 + (zz[i + 2] & M); + zz[i + 2] = (int)c; + c >>>= 32; + c += x_i * y_3 + (zz[i + 3] & M); + zz[i + 3] = (int)c; + c >>>= 32; + c += x_i * y_4 + (zz[i + 4] & M); + zz[i + 4] = (int)c; + c >>>= 32; + c += x_i * y_5 + (zz[i + 5] & M); + zz[i + 5] = (int)c; + c >>>= 32; + c += x_i * y_6 + (zz[i + 6] & M); + zz[i + 6] = (int)c; + c >>>= 32; + c += x_i * y_7 + (zz[i + 7] & M); + zz[i + 7] = (int)c; + c >>>= 32; + c += zc + (zz[i + 8] & M); + zz[i + 8] = (int)c; + zc = c >>> 32; + } + return (int)zc; + } + + public static int mulAddTo(int[] x, int xOff, int[] y, int yOff, int[] zz, int zzOff) { long y_0 = y[yOff + 0] & M; long y_1 = y[yOff + 1] & M; @@ -632,47 +599,44 @@ public abstract class Nat256 return (int)zc; } - public static long mul33AddExt(int w, int[] xx, int xxOff, int[] yy, int yyOff, int[] zz, int zzOff) + public static long mul33Add(int w, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) { - // assert x >>> 31 == 0; - // assert xxOff <= 8; - // assert yyOff <= 8; - // assert zzOff <= 8; + // assert w >>> 31 == 0; long c = 0, wVal = w & M; - long xx00 = xx[xxOff + 0] & M; - c += wVal * xx00 + (yy[yyOff + 0] & M); - zz[zzOff + 0] = (int)c; + long x0 = x[xOff + 0] & M; + c += wVal * x0 + (y[yOff + 0] & M); + z[zOff + 0] = (int)c; c >>>= 32; - long xx01 = xx[xxOff + 1] & M; - c += wVal * xx01 + xx00 + (yy[yyOff + 1] & M); - zz[zzOff + 1] = (int)c; + long x1 = x[xOff + 1] & M; + c += wVal * x1 + x0 + (y[yOff + 1] & M); + z[zOff + 1] = (int)c; c >>>= 32; - long xx02 = xx[xxOff + 2] & M; - c += wVal * xx02 + xx01 + (yy[yyOff + 2] & M); - zz[zzOff + 2] = (int)c; + long x2 = x[xOff + 2] & M; + c += wVal * x2 + x1 + (y[yOff + 2] & M); + z[zOff + 2] = (int)c; c >>>= 32; - long xx03 = xx[xxOff + 3] & M; - c += wVal * xx03 + xx02 + (yy[yyOff + 3] & M); - zz[zzOff + 3] = (int)c; + long x3 = x[xOff + 3] & M; + c += wVal * x3 + x2 + (y[yOff + 3] & M); + z[zOff + 3] = (int)c; c >>>= 32; - long xx04 = xx[xxOff + 4] & M; - c += wVal * xx04 + xx03 + (yy[yyOff + 4] & M); - zz[zzOff + 4] = (int)c; + long x4 = x[xOff + 4] & M; + c += wVal * x4 + x3 + (y[yOff + 4] & M); + z[zOff + 4] = (int)c; c >>>= 32; - long xx05 = xx[xxOff + 5] & M; - c += wVal * xx05 + xx04 + (yy[yyOff + 5] & M); - zz[zzOff + 5] = (int)c; + long x5 = x[xOff + 5] & M; + c += wVal * x5 + x4 + (y[yOff + 5] & M); + z[zOff + 5] = (int)c; c >>>= 32; - long xx06 = xx[xxOff + 6] & M; - c += wVal * xx06 + xx05 + (yy[yyOff + 6] & M); - zz[zzOff + 6] = (int)c; + long x6 = x[xOff + 6] & M; + c += wVal * x6 + x5 + (y[yOff + 6] & M); + z[zOff + 6] = (int)c; c >>>= 32; - long xx07 = xx[xxOff + 7] & M; - c += wVal * xx07 + xx06 + (yy[yyOff + 7] & M); - zz[zzOff + 7] = (int)c; + long x7 = x[xOff + 7] & M; + c += wVal * x7 + x6 + (y[yOff + 7] & M); + z[zOff + 7] = (int)c; c >>>= 32; - c += xx07; + c += x7; return c; } @@ -786,7 +750,25 @@ public abstract class Nat256 c += (z[zOff + 3] & M); z[zOff + 3] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(z, zOff + 4); + return c == 0 ? 0 : Nat.incAt(8, z, zOff, 4); + } + + public static int mul33WordAdd(int x, int y, int[] z, int zOff) + { + // assert x >>> 31 == 0; + // assert zOff <= 5; + + long c = 0, xVal = x & M, yVal = y & M; + c += yVal * xVal + (z[zOff + 0] & M); + z[zOff + 0] = (int)c; + c >>>= 32; + c += yVal + (z[zOff + 1] & M); + z[zOff + 1] = (int)c; + c >>>= 32; + c += (z[zOff + 2] & M); + z[zOff + 2] = (int)c; + c >>>= 32; + return c == 0 ? 0 : Nat.incAt(8, z, zOff, 3); } public static int mulWordDwordAdd(int x, long y, int[] z, int zOff) @@ -802,113 +784,31 @@ public abstract class Nat256 c += (z[zOff + 2] & M); z[zOff + 2] = (int)c; c >>>= 32; - return c == 0 ? 0 : inc(z, zOff + 3); + return c == 0 ? 0 : Nat.incAt(8, z, zOff, 3); } - public static int mulWordExt(int x, int[] y, int[] zz, int zzOff) + public static int mulWord(int x, int[] y, int[] z, int zOff) { - // assert zzOff <= 8; long c = 0, xVal = x & M; int i = 0; do { c += xVal * (y[i] & M); - zz[zzOff + i] = (int)c; + z[zOff + i] = (int)c; c >>>= 32; } while (++i < 8); return (int)c; } - public static int shiftDownBit(int[] x, int xLen, int c) - { - int i = xLen; - while (--i >= 0) - { - int next = x[i]; - x[i] = (next >>> 1) | (c << 31); - c = next; - } - return c << 31; - } - - public static int shiftDownBit(int[] x, int c, int[] z) - { - int i = 8; - while (--i >= 0) - { - int next = x[i]; - z[i] = (next >>> 1) | (c << 31); - c = next; - } - return c << 31; - } - - public static int shiftDownBits(int[] x, int xLen, int bits, int c) - { -// assert bits > 0 && bits < 32; - int i = xLen; - while (--i >= 0) - { - int next = x[i]; - x[i] = (next >>> bits) | (c << -bits); - c = next; - } - return c << -bits; - } - - public static int shiftDownWord(int[] x, int xLen, int c) - { - int i = xLen; - while (--i >= 0) - { - int next = x[i]; - x[i] = c; - c = next; - } - return c; - } - - public static int shiftUpBit(int[] x, int xLen, int c) - { - for (int i = 0; i < xLen; ++i) - { - int next = x[i]; - x[i] = (next << 1) | (c >>> 31); - c = next; - } - return c >>> 31; - } - - public static int shiftUpBit(int[] x, int xOff, int xLen, int c) - { - for (int i = 0; i < xLen; ++i) - { - int next = x[xOff + i]; - x[xOff + i] = (next << 1) | (c >>> 31); - c = next; - } - return c >>> 31; - } - - public static int shiftUpBit(int[] x, int c, int[] z) - { - for (int i = 0; i < 8; ++i) - { - int next = x[i]; - z[i] = (next << 1) | (c >>> 31); - c = next; - } - return c >>> 31; - } - public static void square(int[] x, int[] zz) { long x_0 = x[0] & M; long zz_1; + int c = 0, w; { - int c = 0, i = 7, j = 16; + int i = 7, j = 16; do { long xVal = (x[i--] & M); @@ -922,7 +822,8 @@ public abstract class Nat256 { long p = x_0 * x_0; zz_1 = ((c << 31) & M) | (p >>> 33); - zz[0] = (int)(p >>> 1); + zz[0] = (int)p; + c = (int)(p >>> 32) & 1; } } @@ -931,7 +832,9 @@ public abstract class Nat256 { zz_1 += x_1 * x_0; - zz[1] = (int)zz_1; + w = (int)zz_1; + zz[1] = (w << 1) | c; + c = w >>> 31; zz_2 += zz_1 >>> 32; } @@ -940,7 +843,9 @@ public abstract class Nat256 long zz_4 = zz[4] & M; { zz_2 += x_2 * x_0; - zz[2] = (int)zz_2; + w = (int)zz_2; + zz[2] = (w << 1) | c; + c = w >>> 31; zz_3 += (zz_2 >>> 32) + x_2 * x_1; zz_4 += zz_3 >>> 32; zz_3 &= M; @@ -951,7 +856,9 @@ public abstract class Nat256 long zz_6 = zz[6] & M; { zz_3 += x_3 * x_0; - zz[3] = (int)zz_3; + w = (int)zz_3; + zz[3] = (w << 1) | c; + c = w >>> 31; zz_4 += (zz_3 >>> 32) + x_3 * x_1; zz_5 += (zz_4 >>> 32) + x_3 * x_2; zz_4 &= M; @@ -964,7 +871,9 @@ public abstract class Nat256 long zz_8 = zz[8] & M; { zz_4 += x_4 * x_0; - zz[4] = (int)zz_4; + w = (int)zz_4; + zz[4] = (w << 1) | c; + c = w >>> 31; zz_5 += (zz_4 >>> 32) + x_4 * x_1; zz_6 += (zz_5 >>> 32) + x_4 * x_2; zz_5 &= M; @@ -979,7 +888,9 @@ public abstract class Nat256 long zz_10 = zz[10] & M; { zz_5 += x_5 * x_0; - zz[5] = (int)zz_5; + w = (int)zz_5; + zz[5] = (w << 1) | c; + c = w >>> 31; zz_6 += (zz_5 >>> 32) + x_5 * x_1; zz_7 += (zz_6 >>> 32) + x_5 * x_2; zz_6 &= M; @@ -996,7 +907,9 @@ public abstract class Nat256 long zz_12 = zz[12] & M; { zz_6 += x_6 * x_0; - zz[6] = (int)zz_6; + w = (int)zz_6; + zz[6] = (w << 1) | c; + c = w >>> 31; zz_7 += (zz_6 >>> 32) + x_6 * x_1; zz_8 += (zz_7 >>> 32) + x_6 * x_2; zz_7 &= M; @@ -1015,7 +928,9 @@ public abstract class Nat256 long zz_14 = zz[14] & M; { zz_7 += x_7 * x_0; - zz[7] = (int)zz_7; + w = (int)zz_7; + zz[7] = (w << 1) | c; + c = w >>> 31; zz_8 += (zz_7 >>> 32) + x_7 * x_1; zz_9 += (zz_8 >>> 32) + x_7 * x_2; zz_10 += (zz_9 >>> 32) + x_7 * x_3; @@ -1025,16 +940,29 @@ public abstract class Nat256 zz_14 += zz_13 >>> 32; } - zz[8] = (int)zz_8; - zz[9] = (int)zz_9; - zz[10] = (int)zz_10; - zz[11] = (int)zz_11; - zz[12] = (int)zz_12; - zz[13] = (int)zz_13; - zz[14] = (int)zz_14; - zz[15] += (int)(zz_14 >>> 32); - - shiftUpBit(zz, 16, (int)x_0 << 31); + w = (int)zz_8; + zz[8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[10] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_11; + zz[11] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_12; + zz[12] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_13; + zz[13] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_14; + zz[14] = (w << 1) | c; + c = w >>> 31; + w = zz[15] + (int)(zz_14 >> 32); + zz[15] = (w << 1) | c; } public static void square(int[] x, int xOff, int[] zz, int zzOff) @@ -1042,8 +970,9 @@ public abstract class Nat256 long x_0 = x[xOff + 0] & M; long zz_1; + int c = 0, w; { - int c = 0, i = 7, j = 16; + int i = 7, j = 16; do { long xVal = (x[xOff + i--] & M); @@ -1057,7 +986,8 @@ public abstract class Nat256 { long p = x_0 * x_0; zz_1 = ((c << 31) & M) | (p >>> 33); - zz[zzOff + 0] = (int)(p >>> 1); + zz[zzOff + 0] = (int)p; + c = (int)(p >>> 32) & 1; } } @@ -1066,7 +996,9 @@ public abstract class Nat256 { zz_1 += x_1 * x_0; - zz[zzOff + 1] = (int)zz_1; + w = (int)zz_1; + zz[zzOff + 1] = (w << 1) | c; + c = w >>> 31; zz_2 += zz_1 >>> 32; } @@ -1075,7 +1007,9 @@ public abstract class Nat256 long zz_4 = zz[zzOff + 4] & M; { zz_2 += x_2 * x_0; - zz[zzOff + 2] = (int)zz_2; + w = (int)zz_2; + zz[zzOff + 2] = (w << 1) | c; + c = w >>> 31; zz_3 += (zz_2 >>> 32) + x_2 * x_1; zz_4 += zz_3 >>> 32; zz_3 &= M; @@ -1086,7 +1020,9 @@ public abstract class Nat256 long zz_6 = zz[zzOff + 6] & M; { zz_3 += x_3 * x_0; - zz[zzOff + 3] = (int)zz_3; + w = (int)zz_3; + zz[zzOff + 3] = (w << 1) | c; + c = w >>> 31; zz_4 += (zz_3 >>> 32) + x_3 * x_1; zz_5 += (zz_4 >>> 32) + x_3 * x_2; zz_4 &= M; @@ -1099,7 +1035,9 @@ public abstract class Nat256 long zz_8 = zz[zzOff + 8] & M; { zz_4 += x_4 * x_0; - zz[zzOff + 4] = (int)zz_4; + w = (int)zz_4; + zz[zzOff + 4] = (w << 1) | c; + c = w >>> 31; zz_5 += (zz_4 >>> 32) + x_4 * x_1; zz_6 += (zz_5 >>> 32) + x_4 * x_2; zz_5 &= M; @@ -1114,7 +1052,9 @@ public abstract class Nat256 long zz_10 = zz[zzOff + 10] & M; { zz_5 += x_5 * x_0; - zz[zzOff + 5] = (int)zz_5; + w = (int)zz_5; + zz[zzOff + 5] = (w << 1) | c; + c = w >>> 31; zz_6 += (zz_5 >>> 32) + x_5 * x_1; zz_7 += (zz_6 >>> 32) + x_5 * x_2; zz_6 &= M; @@ -1131,7 +1071,9 @@ public abstract class Nat256 long zz_12 = zz[zzOff + 12] & M; { zz_6 += x_6 * x_0; - zz[zzOff + 6] = (int)zz_6; + w = (int)zz_6; + zz[zzOff + 6] = (w << 1) | c; + c = w >>> 31; zz_7 += (zz_6 >>> 32) + x_6 * x_1; zz_8 += (zz_7 >>> 32) + x_6 * x_2; zz_7 &= M; @@ -1150,7 +1092,9 @@ public abstract class Nat256 long zz_14 = zz[zzOff + 14] & M; { zz_7 += x_7 * x_0; - zz[zzOff + 7] = (int)zz_7; + w = (int)zz_7; + zz[zzOff + 7] = (w << 1) | c; + c = w >>> 31; zz_8 += (zz_7 >>> 32) + x_7 * x_1; zz_9 += (zz_8 >>> 32) + x_7 * x_2; zz_10 += (zz_9 >>> 32) + x_7 * x_3; @@ -1160,31 +1104,29 @@ public abstract class Nat256 zz_14 += zz_13 >>> 32; } - zz[zzOff + 8] = (int)zz_8; - zz[zzOff + 9] = (int)zz_9; - zz[zzOff + 10] = (int)zz_10; - zz[zzOff + 11] = (int)zz_11; - zz[zzOff + 12] = (int)zz_12; - zz[zzOff + 13] = (int)zz_13; - zz[zzOff + 14] = (int)zz_14; - zz[zzOff + 15] += (int)(zz_14 >>> 32); - - shiftUpBit(zz, zzOff, 16, (int)x_0 << 31); - } - - public static int squareWordAddExt(int[] x, int xPos, int[] zz) - { - // assert xPos > 0 && xPos < 8; - long c = 0, xVal = x[xPos] & M; - int i = 0; - do - { - c += xVal * (x[i] & M) + (zz[xPos + i] & M); - zz[xPos + i] = (int)c; - c >>>= 32; - } - while (++i < xPos); - return (int)c; + w = (int)zz_8; + zz[zzOff + 8] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_9; + zz[zzOff + 9] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_10; + zz[zzOff + 10] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_11; + zz[zzOff + 11] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_12; + zz[zzOff + 12] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_13; + zz[zzOff + 13] = (w << 1) | c; + c = w >>> 31; + w = (int)zz_14; + zz[zzOff + 14] = (w << 1) | c; + c = w >>> 31; + w = zz[zzOff + 15] + (int)(zz_14 >> 32); + zz[zzOff + 15] = (w << 1) | c; } public static int sub(int[] x, int[] y, int[] z) @@ -1277,80 +1219,66 @@ public abstract class Nat256 return (int)c; } - // TODO Re-write to allow full range for x? - public static int subDWord(long x, int[] z) + public static int subFrom(int[] x, int[] z) { - long c = -x; - c += (z[0] & M); + long c = 0; + c += (z[0] & M) - (x[0] & M); z[0] = (int)c; c >>= 32; - c += (z[1] & M); + c += (z[1] & M) - (x[1] & M); z[1] = (int)c; c >>= 32; - return c == 0 ? 0 : dec(z, 2); - } - - public static int subExt(int[] xx, int[] yy, int[] zz) - { - long c = 0; - for (int i = 0; i < 16; ++i) - { - c += (xx[i] & M) - (yy[i] & M); - zz[i] = (int)c; - c >>= 32; - } + c += (z[2] & M) - (x[2] & M); + z[2] = (int)c; + c >>= 32; + c += (z[3] & M) - (x[3] & M); + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - (x[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M) - (x[5] & M); + z[5] = (int)c; + c >>= 32; + c += (z[6] & M) - (x[6] & M); + z[6] = (int)c; + c >>= 32; + c += (z[7] & M) - (x[7] & M); + z[7] = (int)c; + c >>= 32; return (int)c; } - public static int subFromExt(int[] x, int xOff, int[] zz, int zzOff) + public static int subFrom(int[] x, int xOff, int[] z, int zOff) { - // assert zzOff <= 8; long c = 0; - c += (zz[zzOff + 0] & M) - (x[xOff + 0] & M); - zz[zzOff + 0] = (int)c; + c += (z[zOff + 0] & M) - (x[xOff + 0] & M); + z[zOff + 0] = (int)c; c >>= 32; - c += (zz[zzOff + 1] & M) - (x[xOff + 1] & M); - zz[zzOff + 1] = (int)c; + c += (z[zOff + 1] & M) - (x[xOff + 1] & M); + z[zOff + 1] = (int)c; c >>= 32; - c += (zz[zzOff + 2] & M) - (x[xOff + 2] & M); - zz[zzOff + 2] = (int)c; + c += (z[zOff + 2] & M) - (x[xOff + 2] & M); + z[zOff + 2] = (int)c; c >>= 32; - c += (zz[zzOff + 3] & M) - (x[xOff + 3] & M); - zz[zzOff + 3] = (int)c; + c += (z[zOff + 3] & M) - (x[xOff + 3] & M); + z[zOff + 3] = (int)c; c >>= 32; - c += (zz[zzOff + 4] & M) - (x[xOff + 4] & M); - zz[zzOff + 4] = (int)c; + c += (z[zOff + 4] & M) - (x[xOff + 4] & M); + z[zOff + 4] = (int)c; c >>= 32; - c += (zz[zzOff + 5] & M) - (x[xOff + 5] & M); - zz[zzOff + 5] = (int)c; + c += (z[zOff + 5] & M) - (x[xOff + 5] & M); + z[zOff + 5] = (int)c; c >>= 32; - c += (zz[zzOff + 6] & M) - (x[xOff + 6] & M); - zz[zzOff + 6] = (int)c; + c += (z[zOff + 6] & M) - (x[xOff + 6] & M); + z[zOff + 6] = (int)c; c >>= 32; - c += (zz[zzOff + 7] & M) - (x[xOff + 7] & M); - zz[zzOff + 7] = (int)c; + c += (z[zOff + 7] & M) - (x[xOff + 7] & M); + z[zOff + 7] = (int)c; c >>= 32; return (int)c; } - public static int subWord(int x, int[] z, int zOff) - { - // assert zOff <= 7; - long c = (z[zOff + 0] & M) - (x & M); - z[zOff + 0] = (int)c; - c >>= 32; - return c == 0 ? 0 : dec(z, zOff + 1); - } - - public static int subWordExt(int x, int[] zz, int zzOff) - { - // assert zzOff <= 15; - long c = (zz[zzOff + 0] & M) - (x & M); - zz[zzOff + 0] = (int)c; - c >>= 32; - return c == 0 ? 0 : decExt(zz, zzOff + 1); - } - public static BigInteger toBigInteger(int[] x) { byte[] bs = new byte[32]; diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat384.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat384.java new file mode 100644 index 00000000..1a55e12c --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat384.java @@ -0,0 +1,44 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.Nat; + +public abstract class Nat384 +{ + public static void mul(int[] x, int[] y, int[] zz) + { + Nat192.mul(x, y, zz); + Nat192.mul(x, 6, y, 6, zz, 12); + + int c18 = Nat192.addToEachOther(zz, 6, zz, 12); + int c12 = c18 + Nat192.addTo(zz, 0, zz, 6, 0); + c18 += Nat192.addTo(zz, 18, zz, 12, c12); + + int[] dx = Nat192.create(), dy = Nat192.create(); + boolean neg = Nat192.diff(x, 6, x, 0, dx, 0) != Nat192.diff(y, 6, y, 0, dy, 0); + + int[] tt = Nat192.createExt(); + Nat192.mul(dx, dy, tt); + + c18 += neg ? Nat.addTo(12, tt, 0, zz, 6) : Nat.subFrom(12, tt, 0, zz, 6); + Nat.addWordAt(24, c18, zz, 18); + } + + public static void square(int[] x, int[] zz) + { + Nat192.square(x, zz); + Nat192.square(x, 6, zz, 12); + + int c18 = Nat192.addToEachOther(zz, 6, zz, 12); + int c12 = c18 + Nat192.addTo(zz, 0, zz, 6, 0); + c18 += Nat192.addTo(zz, 18, zz, 12, c12); + + int[] dx = Nat192.create(); + Nat192.diff(x, 6, x, 0, dx, 0); + + int[] tt = Nat192.createExt(); + Nat192.square(dx, tt); + + c18 += Nat.subFrom(12, tt, 0, zz, 6); + Nat.addWordAt(24, c18, zz, 18); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat512.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat512.java index a43008f0..59399617 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat512.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/Nat512.java @@ -20,9 +20,9 @@ public abstract class Nat512 Nat256.mul(dx, dy, tt); c24 += neg ? Nat.addTo(16, tt, 0, zz, 8) : Nat.subFrom(16, tt, 0, zz, 8); - Nat.addWordExt(16, c24, zz, 24); + Nat.addWordAt(32, c24, zz, 24); } - + public static void square(int[] x, int[] zz) { Nat256.square(x, zz); @@ -39,6 +39,6 @@ public abstract class Nat512 Nat256.square(dx, tt); c24 += Nat.subFrom(16, tt, 0, zz, 8); - Nat.addWordExt(16, c24, zz, 24); + Nat.addWordAt(32, c24, zz, 24); } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java index b26348cd..87d9f10c 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java @@ -5,7 +5,11 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECMultiplier; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.GLVMultiplier; +import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism; +import org.bouncycastle.math.ec.endo.GLVTypeBParameters; import org.bouncycastle.math.field.FiniteFields; import org.bouncycastle.util.encoders.Hex; @@ -68,6 +72,11 @@ public class SecP192K1Curve extends ECCurve return new SecP192K1Point(this, x, y, withCompression); } + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP192K1Point(this, x, y, zs, withCompression); + } + protected ECPoint decompressPoint(int yTilde, BigInteger X1) { ECFieldElement x = fromBigInteger(X1); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java index 39fcd3d9..20827e55 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Field.java @@ -2,15 +2,18 @@ package org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import org.bouncycastle.math.ec.Nat; + public class SecP192K1Field { // 2^192 - 2^32 - 2^12 - 2^8 - 2^7 - 2^6 - 2^3 - 1 static final int[] P = new int[]{ 0xFFFFEE37, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; - private static final int P5 = 0xFFFFFFFF; - private static final int[] PExt = new int[]{ 0x013C4FD1, 0x00002392, 0x00000001, 0x00000000, 0x00000000, + static final int[] PExt = new int[]{ 0x013C4FD1, 0x00002392, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0xFFFFDC6E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFEC3B02F, 0xFFFFDC6D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00002391, 0x00000002 }; + private static final int P5 = 0xFFFFFFFF; private static final int PExt11 = 0xFFFFFFFF; - private static final long PInv = 0x00000001000011C9L; private static final int PInv33 = 0x11C9; public static void add(int[] x, int[] y, int[] z) @@ -18,26 +21,28 @@ public class SecP192K1Field int c = Nat192.add(x, y, z); if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) { - Nat192.addDWord(PInv, z, 0); + Nat.add33To(6, PInv33, z); } } public static void addExt(int[] xx, int[] yy, int[] zz) { - int c = Nat192.addExt(xx, yy, zz); - if (c != 0 || (zz[11] == PExt11 && Nat192.gteExt(zz, PExt))) + int c = Nat.add(12, xx, yy, zz); + if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt))) { - Nat192.subExt(zz, PExt, zz); + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(12, zz, PExtInv.length); + } } } public static void addOne(int[] x, int[] z) { - System.arraycopy(x, 0, z, 0, 6); - int c = Nat192.inc(z, 0); + int c = Nat.inc(6, x, z); if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) { - Nat192.addDWord(PInv, z, 0); + Nat.add33To(6, PInv33, z); } } @@ -46,7 +51,7 @@ public class SecP192K1Field int[] z = Nat192.fromBigInteger(x); if (z[5] == P5 && Nat192.gte(z, P)) { - Nat192.addDWord(PInv, z, 0); + Nat192.subFrom(P, z); } return z; } @@ -55,12 +60,12 @@ public class SecP192K1Field { if ((x[0] & 1) == 0) { - Nat192.shiftDownBit(x, 0, z); + Nat.shiftDownBit(6, x, 0, z); } else { int c = Nat192.add(x, P, z); - Nat192.shiftDownBit(z, c, z); + Nat.shiftDownBit(6, z, c); } } @@ -71,6 +76,18 @@ public class SecP192K1Field reduce(tt, z); } + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat192.mulAddTo(x, y, zz); + if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(12, zz, PExtInv.length); + } + } + } + public static void negate(int[] x, int[] z) { if (Nat192.isZero(x)) @@ -85,14 +102,23 @@ public class SecP192K1Field public static void reduce(int[] xx, int[] z) { - long c = Nat192.mul33AddExt(PInv33, xx, 6, xx, 0, z, 0); - c = Nat192.mul33DWordAdd(PInv33, c, z, 0); + long cc = Nat192.mul33Add(PInv33, xx, 6, xx, 0, z, 0); + int c = Nat192.mul33DWordAdd(PInv33, cc, z, 0); // assert c == 0L || c == 1L; if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) { - Nat192.addDWord(PInv, z, 0); + Nat.add33To(6, PInv33, z); + } + } + + public static void reduce32(int x, int[] z) + { + if ((x != 0 && Nat192.mul33WordAdd(PInv33, x, z, 0) != 0) + || (z[5] == P5 && Nat192.gte(z, P))) + { + Nat.add33To(6, PInv33, z); } } @@ -123,25 +149,28 @@ public class SecP192K1Field int c = Nat192.sub(x, y, z); if (c != 0) { - Nat192.subDWord(PInv, z); + Nat.sub33From(6, PInv33, z); } } public static void subtractExt(int[] xx, int[] yy, int[] zz) { - int c = Nat192.subExt(xx, yy, zz); + int c = Nat.sub(12, xx, yy, zz); if (c != 0) { - Nat192.addExt(zz, PExt, zz); + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(12, zz, PExtInv.length); + } } } public static void twice(int[] x, int[] z) { - int c = Nat192.shiftUpBit(x, 0, z); + int c = Nat.shiftUpBit(6, x, 0, z); if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) { - Nat192.addDWord(PInv, z, 0); + Nat.add33To(6, PInv33, z); } } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java index 91d576d1..3e70754b 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java @@ -186,7 +186,7 @@ public class SecP192K1FieldElement extends ECFieldElement int[] t2 = x3; SecP192K1Field.square(t1, t2); - return Arrays.areEqual(x1, t2) ? new SecP192K1FieldElement(t1) : null; + return Nat192.eq(x1, t2) ? new SecP192K1FieldElement(t1) : null; } public boolean equals(Object other) @@ -202,11 +202,11 @@ public class SecP192K1FieldElement extends ECFieldElement } SecP192K1FieldElement o = (SecP192K1FieldElement)other; - return Arrays.areEqual(x, o.x); + return Nat192.eq(x, o.x); } public int hashCode() { - return Q.hashCode() ^ Arrays.hashCode(x); + return Q.hashCode() ^ Arrays.hashCode(x, 0, 6); } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java index da9e5e24..d3802086 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java @@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.Nat; public class SecP192K1Point extends ECPoint { @@ -92,8 +93,9 @@ public class SecP192K1Point extends ECPoint SecP192K1FieldElement Z1 = (SecP192K1FieldElement)this.zs[0]; SecP192K1FieldElement Z2 = (SecP192K1FieldElement)b.getZCoord(0); + int c; int[] tt1 = Nat192.createExt(); - int[] tt2 = Nat192.createExt(); + int[] t2 = Nat192.create(); int[] t3 = Nat192.create(); int[] t4 = Nat192.create(); @@ -109,7 +111,7 @@ public class SecP192K1Point extends ECPoint S2 = t3; SecP192K1Field.square(Z1.x, S2); - U2 = tt2; + U2 = t2; SecP192K1Field.multiply(S2, X2.x, U2); SecP192K1Field.multiply(S2, Z1.x, S2); @@ -138,7 +140,7 @@ public class SecP192K1Point extends ECPoint int[] H = Nat192.create(); SecP192K1Field.subtract(U1, U2, H); - int[] R = tt2; + int[] R = t2; SecP192K1Field.subtract(S1, S2, R); // Check if b == this or b == -this @@ -163,19 +165,20 @@ public class SecP192K1Point extends ECPoint int[] V = t3; SecP192K1Field.multiply(HSquared, U1, V); + SecP192K1Field.negate(G, G); Nat192.mul(S1, G, tt1); + c = Nat192.addBothTo(V, V, G); + SecP192K1Field.reduce32(c, G); + SecP192K1FieldElement X3 = new SecP192K1FieldElement(t4); SecP192K1Field.square(R, X3.x); - SecP192K1Field.add(X3.x, G, X3.x); - SecP192K1Field.subtract(X3.x, V, X3.x); - SecP192K1Field.subtract(X3.x, V, X3.x); + SecP192K1Field.subtract(X3.x, G, X3.x); SecP192K1FieldElement Y3 = new SecP192K1FieldElement(G); SecP192K1Field.subtract(V, X3.x, Y3.x); - Nat192.mul(Y3.x, R, tt2); - SecP192K1Field.subtractExt(tt2, tt1, tt2); - SecP192K1Field.reduce(tt2, Y3.x); + SecP192K1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP192K1Field.reduce(tt1, Y3.x); SecP192K1FieldElement Z3 = new SecP192K1FieldElement(H); if (!Z1IsOne) @@ -210,27 +213,27 @@ public class SecP192K1Point extends ECPoint SecP192K1FieldElement X1 = (SecP192K1FieldElement)this.x, Z1 = (SecP192K1FieldElement)this.zs[0]; + int c; + int[] Y1Squared = Nat192.create(); SecP192K1Field.square(Y1.x, Y1Squared); int[] T = Nat192.create(); SecP192K1Field.square(Y1Squared, T); - int[] t1 = Nat192.create(); - SecP192K1Field.square(X1.x, t1); - int[] M = Nat192.create(); - SecP192K1Field.twice(t1, M); - SecP192K1Field.add(M, t1, M); + SecP192K1Field.square(X1.x, M); + c = Nat192.addBothTo(M, M, M); + SecP192K1Field.reduce32(c, M); int[] S = Y1Squared; SecP192K1Field.multiply(Y1Squared, X1.x, S); - SecP192K1Field.twice(S, S); - SecP192K1Field.twice(S, S); + c = Nat.shiftUpBits(6, S, 2, 0); + SecP192K1Field.reduce32(c, S); - SecP192K1Field.twice(T, t1); - SecP192K1Field.twice(t1, t1); - SecP192K1Field.twice(t1, t1); + int[] t1 = Nat192.create(); + c = Nat.shiftUpBits(6, T, 3, 0, t1); + SecP192K1Field.reduce32(c, t1); SecP192K1FieldElement X3 = new SecP192K1FieldElement(T); SecP192K1Field.square(M, X3.x); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java index 8e00c5bc..5491609b 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java @@ -69,6 +69,11 @@ public class SecP192R1Curve extends ECCurve return new SecP192R1Point(this, x, y, withCompression); } + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP192R1Point(this, x, y, zs, withCompression); + } + protected ECPoint decompressPoint(int yTilde, BigInteger X1) { ECFieldElement x = fromBigInteger(X1); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java index 02d0b72e..2f77815b 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Field.java @@ -2,15 +2,19 @@ package org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import org.bouncycastle.math.ec.Nat; + public class SecP192R1Field { private static final long M = 0xFFFFFFFFL; // 2^192 - 2^64 - 1 static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; - private static final int P5 = 0xFFFFFFFF; - private static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001, + static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000002, 0x00000000, 0x00000001, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFE, + 0xFFFFFFFF, 0x00000001, 0x00000000, 0x00000002 }; + private static final int P5 = 0xFFFFFFFF; private static final int PExt11 = 0xFFFFFFFF; public static void add(int[] x, int[] y, int[] z) @@ -18,26 +22,28 @@ public class SecP192R1Field int c = Nat192.add(x, y, z); if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) { - Nat192.sub(z, P, z); + addPInvTo(z); } } public static void addExt(int[] xx, int[] yy, int[] zz) { - int c = Nat192.addExt(xx, yy, zz); - if (c != 0 || (zz[11] == PExt11 && Nat192.gteExt(zz, PExt))) + int c = Nat.add(12, xx, yy, zz); + if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt))) { - Nat192.subExt(zz, PExt, zz); + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(12, zz, PExtInv.length); + } } } public static void addOne(int[] x, int[] z) { - System.arraycopy(x, 0, z, 0, 6); - int c = Nat192.inc(z, 0); + int c = Nat.inc(6, x, z); if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) { - Nat192.sub(z, P, z); + addPInvTo(z); } } @@ -46,7 +52,7 @@ public class SecP192R1Field int[] z = Nat192.fromBigInteger(x); if (z[5] == P5 && Nat192.gte(z, P)) { - Nat192.sub(z, P, z); + Nat192.subFrom(P, z); } return z; } @@ -55,12 +61,12 @@ public class SecP192R1Field { if ((x[0] & 1) == 0) { - Nat192.shiftDownBit(x, 0, z); + Nat.shiftDownBit(6, x, 0, z); } else { int c = Nat192.add(x, P, z); - Nat192.shiftDownBit(z, c, z); + Nat.shiftDownBit(6, z, c); } } @@ -71,6 +77,18 @@ public class SecP192R1Field reduce(tt, z); } + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat192.mulAddTo(x, y, zz); + if (c != 0 || (zz[11] == PExt11 && Nat.gte(12, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(12, zz, PExtInv.length); + } + } + } + public static void negate(int[] x, int[] z) { if (Nat192.isZero(x)) @@ -93,7 +111,7 @@ public class SecP192R1Field long cc = 0; cc += (xx[0] & M) + t0; - z[0] = (int)cc; + int z0 = (int)cc; cc >>= 32; cc += (xx[1] & M) + t1; z[1] = (int)cc; @@ -103,7 +121,7 @@ public class SecP192R1Field t1 += xx09; cc += (xx[2] & M) + t0; - z[2] = (int)cc; + long z2 = cc & M; cc >>= 32; cc += (xx[3] & M) + t1; z[3] = (int)cc; @@ -119,15 +137,57 @@ public class SecP192R1Field z[5] = (int)cc; cc >>= 32; - int c = (int)cc; - while (c > 0) + z2 += cc; + + cc += (z0 & M); + z[0] = (int)cc; + cc >>= 32; + if (cc != 0) { - c += Nat192.sub(z, P, z); + cc += (z[1] & M); + z[1] = (int)cc; + z2 += cc >> 32; } + z[2] = (int)z2; + cc = z2 >> 32; - if (z[5] == P5 && Nat192.gte(z, P)) +// assert cc == 0 || cc == 1; + + if ((cc != 0 && Nat.incAt(6, z, 3) != 0) + || (z[5] == P5 && Nat192.gte(z, P))) { - Nat192.sub(z, P, z); + addPInvTo(z); + } + } + + public static void reduce32(int x, int[] z) + { + long cc = 0; + + if (x != 0) + { + long xx06 = x & M; + + cc += (z[0] & M) + xx06; + z[0] = (int)cc; + cc >>= 32; + if (cc != 0) + { + cc += (z[1] & M); + z[1] = (int)cc; + cc >>= 32; + } + cc += (z[2] & M) + xx06; + z[2] = (int)cc; + cc >>= 32; + +// assert cc == 0 || cc == 1; + } + + if ((cc != 0 && Nat.incAt(6, z, 3) != 0) + || (z[5] == P5 && Nat192.gte(z, P))) + { + addPInvTo(z); } } @@ -158,25 +218,68 @@ public class SecP192R1Field int c = Nat192.sub(x, y, z); if (c != 0) { - Nat192.add(z, P, z); + subPInvFrom(z); } } public static void subtractExt(int[] xx, int[] yy, int[] zz) { - int c = Nat192.subExt(xx, yy, zz); + int c = Nat.sub(12, xx, yy, zz); if (c != 0) { - Nat192.addExt(zz, PExt, zz); + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(12, zz, PExtInv.length); + } } } public static void twice(int[] x, int[] z) { - int c = Nat192.shiftUpBit(x, 0, z); + int c = Nat.shiftUpBit(6, x, 0, z); if (c != 0 || (z[5] == P5 && Nat192.gte(z, P))) { - Nat192.sub(z, P, z); + addPInvTo(z); + } + } + + private static void addPInvTo(int[] z) + { + long c = (z[0] & M) + 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + } + c += (z[2] & M) + 1; + z[2] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.incAt(6, z, 3); + } + } + + private static void subPInvFrom(int[] z) + { + long c = (z[0] & M) - 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + } + c += (z[2] & M) - 1; + z[2] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.decAt(6, z, 3); } } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java index cc1a231d..15d7de7d 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java @@ -163,7 +163,7 @@ public class SecP192R1FieldElement extends ECFieldElement SecP192R1Field.squareN(t1, 62, t1); SecP192R1Field.square(t1, t2); - return Arrays.areEqual(x1, t2) ? new SecP192R1FieldElement(t1) : null; + return Nat192.eq(x1, t2) ? new SecP192R1FieldElement(t1) : null; } public boolean equals(Object other) @@ -179,11 +179,11 @@ public class SecP192R1FieldElement extends ECFieldElement } SecP192R1FieldElement o = (SecP192R1FieldElement)other; - return Arrays.areEqual(x, o.x); + return Nat192.eq(x, o.x); } public int hashCode() { - return Q.hashCode() ^ Arrays.hashCode(x); + return Q.hashCode() ^ Arrays.hashCode(x, 0, 6); } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java index fb62217d..9a629ae4 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java @@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.Nat; public class SecP192R1Point extends ECPoint { @@ -91,8 +92,9 @@ public class SecP192R1Point extends ECPoint SecP192R1FieldElement Z1 = (SecP192R1FieldElement)this.zs[0]; SecP192R1FieldElement Z2 = (SecP192R1FieldElement)b.getZCoord(0); + int c; int[] tt1 = Nat192.createExt(); - int[] tt2 = Nat192.createExt(); + int[] t2 = Nat192.create(); int[] t3 = Nat192.create(); int[] t4 = Nat192.create(); @@ -108,7 +110,7 @@ public class SecP192R1Point extends ECPoint S2 = t3; SecP192R1Field.square(Z1.x, S2); - U2 = tt2; + U2 = t2; SecP192R1Field.multiply(S2, X2.x, U2); SecP192R1Field.multiply(S2, Z1.x, S2); @@ -137,7 +139,7 @@ public class SecP192R1Point extends ECPoint int[] H = Nat192.create(); SecP192R1Field.subtract(U1, U2, H); - int[] R = tt2; + int[] R = t2; SecP192R1Field.subtract(S1, S2, R); // Check if b == this or b == -this @@ -162,19 +164,20 @@ public class SecP192R1Point extends ECPoint int[] V = t3; SecP192R1Field.multiply(HSquared, U1, V); + SecP192R1Field.negate(G, G); Nat192.mul(S1, G, tt1); + c = Nat192.addBothTo(V, V, G); + SecP192R1Field.reduce32(c, G); + SecP192R1FieldElement X3 = new SecP192R1FieldElement(t4); SecP192R1Field.square(R, X3.x); - SecP192R1Field.add(X3.x, G, X3.x); - SecP192R1Field.subtract(X3.x, V, X3.x); - SecP192R1Field.subtract(X3.x, V, X3.x); + SecP192R1Field.subtract(X3.x, G, X3.x); SecP192R1FieldElement Y3 = new SecP192R1FieldElement(G); SecP192R1Field.subtract(V, X3.x, Y3.x); - Nat192.mul(Y3.x, R, tt2); - SecP192R1Field.subtractExt(tt2, tt1, tt2); - SecP192R1Field.reduce(tt2, Y3.x); + SecP192R1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP192R1Field.reduce(tt1, Y3.x); SecP192R1FieldElement Z3 = new SecP192R1FieldElement(H); if (!Z1IsOne) @@ -209,6 +212,7 @@ public class SecP192R1Point extends ECPoint SecP192R1FieldElement X1 = (SecP192R1FieldElement)this.x, Z1 = (SecP192R1FieldElement)this.zs[0]; + int c; int[] t1 = Nat192.create(); int[] t2 = Nat192.create(); @@ -232,17 +236,16 @@ public class SecP192R1Point extends ECPoint int[] M = t2; SecP192R1Field.add(X1.x, Z1Squared, M); SecP192R1Field.multiply(M, t1, M); - SecP192R1Field.twice(M, t1); - SecP192R1Field.add(M, t1, M); + c = Nat192.addBothTo(M, M, M); + SecP192R1Field.reduce32(c, M); int[] S = Y1Squared; SecP192R1Field.multiply(Y1Squared, X1.x, S); - SecP192R1Field.twice(S, S); - SecP192R1Field.twice(S, S); + c = Nat.shiftUpBits(6, S, 2, 0); + SecP192R1Field.reduce32(c, S); - SecP192R1Field.twice(T, t1); - SecP192R1Field.twice(t1, t1); - SecP192R1Field.twice(t1, t1); + c = Nat.shiftUpBits(6, T, 3, 0, t1); + SecP192R1Field.reduce32(c, t1); SecP192R1FieldElement X3 = new SecP192R1FieldElement(T); SecP192R1Field.square(M, X3.x); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java new file mode 100644 index 00000000..8323de1d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java @@ -0,0 +1,107 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECMultiplier; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.GLVMultiplier; +import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism; +import org.bouncycastle.math.ec.endo.GLVTypeBParameters; +import org.bouncycastle.math.field.FiniteFields; +import org.bouncycastle.util.encoders.Hex; + +public class SecP224K1Curve extends ECCurve +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D")); + + private static final int SECP224K1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP224K1Point infinity; + + public SecP224K1Curve() + { + super(FiniteFields.getPrimeField(q)); + + this.infinity = new SecP224K1Point(this, null, null); + + this.a = fromBigInteger(ECConstants.ZERO); + this.b = fromBigInteger(BigInteger.valueOf(5)); + this.order = new BigInteger(1, Hex.decode("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7")); + this.cofactor = BigInteger.valueOf(1); + this.coord = SECP224K1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP224K1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP224K1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP224K1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP224K1Point(this, x, y, zs, withCompression); + } + + protected ECPoint decompressPoint(int yTilde, BigInteger X1) + { + ECFieldElement x = fromBigInteger(X1); + ECFieldElement alpha = x.square().multiply(x).add(getB()); + ECFieldElement beta = alpha.sqrt(); + + // + // if we can't find a sqrt we haven't got a point on the + // curve - run! + // + if (beta == null) + { + throw new RuntimeException("Invalid point compression"); + } + + if (beta.testBitZero() != (yTilde == 1)) + { + // Use the other root + beta = beta.negate(); + } + + return new SecP224K1Point(this, x, beta, true); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java new file mode 100644 index 00000000..0a9eebc8 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Field.java @@ -0,0 +1,177 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.Nat; + +public class SecP224K1Field +{ + // 2^224 - 2^32 - 2^12 - 2^11 - 2^9 - 2^7 - 2^4 - 2 - 1 + static final int[] P = new int[]{ 0xFFFFE56D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x02C23069, 0x00003526, 0x00000001, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0xFFFFCADA, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFD3DCF97, 0xFFFFCAD9, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00003525, 0x00000002 }; + private static final int P6 = 0xFFFFFFFF; + private static final int PExt13 = 0xFFFFFFFF; + private static final int PInv33 = 0x1A93; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat224.add(x, y, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(14, xx, yy, zz); + if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(14, zz, PExtInv.length); + } + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(7, x, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat224.fromBigInteger(x); + if (z[6] == P6 && Nat224.gte(z, P)) + { + Nat.add33To(7, PInv33, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(7, x, 0, z); + } + else + { + int c = Nat224.add(x, P, z); + Nat.shiftDownBit(7, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat224.createExt(); + Nat224.mul(x, y, tt); + reduce(tt, z); + } + + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat224.mulAddTo(x, y, zz); + if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(14, zz, PExtInv.length); + } + } + } + + public static void negate(int[] x, int[] z) + { + if (Nat224.isZero(x)) + { + Nat224.zero(z); + } + else + { + Nat224.sub(P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long cc = Nat224.mul33Add(PInv33, xx, 7, xx, 0, z, 0); + int c = Nat224.mul33DWordAdd(PInv33, cc, z, 0); + + // assert c == 0L || c == 1L; + + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } + + public static void reduce32(int x, int[] z) + { + if ((x != 0 && Nat224.mul33WordAdd(PInv33, x, z, 0) != 0) + || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat224.createExt(); + Nat224.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat224.createExt(); + Nat224.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat224.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat224.sub(x, y, z); + if (c != 0) + { + Nat.sub33From(7, PInv33, z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(14, xx, yy, zz); + if (c != 0) + { + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(14, zz, PExtInv.length); + } + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(7, x, 0, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + Nat.add33To(7, PInv33, z); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java new file mode 100644 index 00000000..5496c30a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java @@ -0,0 +1,242 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.Mod; +import org.bouncycastle.util.Arrays; + +public class SecP224K1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP224K1Curve.q; + + // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q) + private static final int[] PRECOMP_POW2 = new int[]{ 0x33bfd202, 0xdcfad133, 0x2287624a, 0xc3811ba8, + 0xa85558fc, 0x1eaef5d7, 0x8edf154c }; + + protected int[] x; + + public SecP224K1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP224K1FieldElement"); + } + + this.x = SecP224K1Field.fromBigInteger(x); + } + + public SecP224K1FieldElement() + { + this.x = Nat224.create(); + } + + protected SecP224K1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat224.isZero(x); + } + + public boolean isOne() + { + return Nat224.isOne(x); + } + + public boolean testBitZero() + { + return Nat224.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat224.toBigInteger(x); + } + + public String getFieldName() + { + return "SecP224K1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224K1Field.add(x, ((SecP224K1FieldElement)b).x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat224.create(); + SecP224K1Field.addOne(x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224K1Field.subtract(x, ((SecP224K1FieldElement)b).x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224K1Field.multiply(x, ((SecP224K1FieldElement)b).x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat224.create(); + Mod.invert(SecP224K1Field.P, ((SecP224K1FieldElement)b).x, z); + SecP224K1Field.multiply(z, x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat224.create(); + SecP224K1Field.negate(x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat224.create(); + SecP224K1Field.square(x, z); + return new SecP224K1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP224K1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat224.create(); + Mod.invert(SecP224K1Field.P, x, z); + return new SecP224K1FieldElement(z); + } + + // D.1.4 91 + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + /* + * Q == 8m + 5, so we use Pocklington's method for this case. + * + * First, raise this element to the exponent 2^221 - 2^29 - 2^9 - 2^8 - 2^6 - 2^4 - 2^1 (i.e. m + 1) + * + * Breaking up the exponent's binary representation into "repunits", we get: + * { 191 1s } { 1 0s } { 19 1s } { 2 0s } { 1 1s } { 1 0s} { 1 1s } { 1 0s} { 3 1s } { 1 0s} + * + * Therefore we need an addition chain containing 1, 3, 19, 191 (the lengths of the repunits) + * We use: [1], 2, [3], 4, 8, 11, [19], 23, 42, 84, 107, [191] + */ + + int[] x1 = this.x; + if (Nat224.isZero(x1) || Nat224.isOne(x1)) + { + return this; + } + + int[] x2 = Nat224.create(); + SecP224K1Field.square(x1, x2); + SecP224K1Field.multiply(x2, x1, x2); + int[] x3 = x2; + SecP224K1Field.square(x2, x3); + SecP224K1Field.multiply(x3, x1, x3); + int[] x4 = Nat224.create(); + SecP224K1Field.square(x3, x4); + SecP224K1Field.multiply(x4, x1, x4); + int[] x8 = Nat224.create(); + SecP224K1Field.squareN(x4, 4, x8); + SecP224K1Field.multiply(x8, x4, x8); + int[] x11 = Nat224.create(); + SecP224K1Field.squareN(x8, 3, x11); + SecP224K1Field.multiply(x11, x3, x11); + int[] x19 = x11; + SecP224K1Field.squareN(x11, 8, x19); + SecP224K1Field.multiply(x19, x8, x19); + int[] x23 = x8; + SecP224K1Field.squareN(x19, 4, x23); + SecP224K1Field.multiply(x23, x4, x23); + int[] x42 = x4; + SecP224K1Field.squareN(x23, 19, x42); + SecP224K1Field.multiply(x42, x19, x42); + int[] x84 = Nat224.create(); + SecP224K1Field.squareN(x42, 42, x84); + SecP224K1Field.multiply(x84, x42, x84); + int[] x107 = x42; + SecP224K1Field.squareN(x84, 23, x107); + SecP224K1Field.multiply(x107, x23, x107); + int[] x191 = x23; + SecP224K1Field.squareN(x107, 84, x191); + SecP224K1Field.multiply(x191, x84, x191); + + int[] t1 = x191; + SecP224K1Field.squareN(t1, 20, t1); + SecP224K1Field.multiply(t1, x19, t1); + SecP224K1Field.squareN(t1, 3, t1); + SecP224K1Field.multiply(t1, x1, t1); + SecP224K1Field.squareN(t1, 2, t1); + SecP224K1Field.multiply(t1, x1, t1); + SecP224K1Field.squareN(t1, 4, t1); + SecP224K1Field.multiply(t1, x3, t1); + SecP224K1Field.square(t1, t1); + + int[] t2 = x84; + SecP224K1Field.square(t1, t2); + + if (Nat224.eq(x1, t2)) + { + return new SecP224K1FieldElement(t1); + } + + /* + * If the first guess is incorrect, we multiply by a precomputed power of 2 to get the second guess, + * which is ((4x)^(m + 1))/2 mod Q + */ + SecP224K1Field.multiply(t1, PRECOMP_POW2, t1); + + SecP224K1Field.square(t1, t2); + + if (Nat224.eq(x1, t2)) + { + return new SecP224K1FieldElement(t1); + } + + return null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP224K1FieldElement)) + { + return false; + } + + SecP224K1FieldElement o = (SecP224K1FieldElement)other; + return Nat224.eq(x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 7); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java new file mode 100644 index 00000000..6b72dbe7 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java @@ -0,0 +1,314 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.Nat; + +public class SecP224K1Point extends ECPoint +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, + boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP224K1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + protected boolean getCompressionYTilde() + { + return this.getAffineYCoord().testBitZero(); + } + + // B.3 pg 62 + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.x, Y1 = (SecP224K1FieldElement)this.y; + SecP224K1FieldElement X2 = (SecP224K1FieldElement)b.getXCoord(), Y2 = (SecP224K1FieldElement)b.getYCoord(); + + SecP224K1FieldElement Z1 = (SecP224K1FieldElement)this.zs[0]; + SecP224K1FieldElement Z2 = (SecP224K1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat224.createExt(); + int[] t2 = Nat224.create(); + int[] t3 = Nat224.create(); + int[] t4 = Nat224.create(); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP224K1Field.square(Z1.x, S2); + + U2 = t2; + SecP224K1Field.multiply(S2, X2.x, U2); + + SecP224K1Field.multiply(S2, Z1.x, S2); + SecP224K1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP224K1Field.square(Z2.x, S1); + + U1 = tt1; + SecP224K1Field.multiply(S1, X1.x, U1); + + SecP224K1Field.multiply(S1, Z2.x, S1); + SecP224K1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat224.create(); + SecP224K1Field.subtract(U1, U2, H); + + int[] R = t2; + SecP224K1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat224.isZero(H)) + { + if (Nat224.isZero(R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP224K1Field.square(H, HSquared); + + int[] G = Nat224.create(); + SecP224K1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP224K1Field.multiply(HSquared, U1, V); + + SecP224K1Field.negate(G, G); + Nat224.mul(S1, G, tt1); + + c = Nat224.addBothTo(V, V, G); + SecP224K1Field.reduce32(c, G); + + SecP224K1FieldElement X3 = new SecP224K1FieldElement(t4); + SecP224K1Field.square(R, X3.x); + SecP224K1Field.subtract(X3.x, G, X3.x); + + SecP224K1FieldElement Y3 = new SecP224K1FieldElement(G); + SecP224K1Field.subtract(V, X3.x, Y3.x); + SecP224K1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP224K1Field.reduce(tt1, Y3.x); + + SecP224K1FieldElement Z3 = new SecP224K1FieldElement(H); + if (!Z1IsOne) + { + SecP224K1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP224K1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[] { Z3 }; + + return new SecP224K1Point(curve, X3, Y3, zs, this.withCompression); + } + + // B.3 pg 62 + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP224K1FieldElement Y1 = (SecP224K1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP224K1FieldElement X1 = (SecP224K1FieldElement)this.x, Z1 = (SecP224K1FieldElement)this.zs[0]; + + int c; + + int[] Y1Squared = Nat224.create(); + SecP224K1Field.square(Y1.x, Y1Squared); + + int[] T = Nat224.create(); + SecP224K1Field.square(Y1Squared, T); + + int[] M = Nat224.create(); + SecP224K1Field.square(X1.x, M); + c = Nat224.addBothTo(M, M, M); + SecP224K1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP224K1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(7, S, 2, 0); + SecP224K1Field.reduce32(c, S); + + int[] t1 = Nat224.create(); + c = Nat.shiftUpBits(7, T, 3, 0, t1); + SecP224K1Field.reduce32(c, t1); + + SecP224K1FieldElement X3 = new SecP224K1FieldElement(T); + SecP224K1Field.square(M, X3.x); + SecP224K1Field.subtract(X3.x, S, X3.x); + SecP224K1Field.subtract(X3.x, S, X3.x); + + SecP224K1FieldElement Y3 = new SecP224K1FieldElement(S); + SecP224K1Field.subtract(S, X3.x, Y3.x); + SecP224K1Field.multiply(Y3.x, M, Y3.x); + SecP224K1Field.subtract(Y3.x, t1, Y3.x); + + SecP224K1FieldElement Z3 = new SecP224K1FieldElement(M); + SecP224K1Field.twice(Y1.x, Z3.x); + if (!Z1.isOne()) + { + SecP224K1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP224K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + // D.3.2 pg 102 (see Note:) + public ECPoint subtract(ECPoint b) + { + if (b.isInfinity()) + { + return this; + } + + // Add -b + return add(b.negate()); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP224K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java new file mode 100644 index 00000000..bbb02701 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java @@ -0,0 +1,105 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.field.FiniteFields; +import org.bouncycastle.util.encoders.Hex; + +public class SecP224R1Curve extends ECCurve +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001")); + + private static final int SecP224R1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP224R1Point infinity; + + public SecP224R1Curve() + { + super(FiniteFields.getPrimeField(q)); + + this.infinity = new SecP224R1Point(this, null, null); + + this.a = fromBigInteger(new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"))); + this.b = fromBigInteger(new BigInteger(1, + Hex.decode("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"))); + this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D")); + this.cofactor = BigInteger.valueOf(1); + + this.coord = SecP224R1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP224R1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP224R1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP224R1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP224R1Point(this, x, y, zs, withCompression); + } + + protected ECPoint decompressPoint(int yTilde, BigInteger X1) + { + ECFieldElement x = fromBigInteger(X1); + ECFieldElement alpha = x.square().add(getA()).multiply(x).add(getB()); + ECFieldElement beta = alpha.sqrt(); + + // + // if we can't find a sqrt we haven't got a point on the + // curve - run! + // + if (beta == null) + { + throw new RuntimeException("Invalid point compression"); + } + + if (beta.testBitZero() != (yTilde == 1)) + { + // Use the other root + beta = beta.negate(); + } + + return new SecP224R1Point(this, x, beta, true); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java new file mode 100644 index 00000000..d39fb4dd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Field.java @@ -0,0 +1,297 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.Nat; + +public class SecP224R1Field +{ + private static final long M = 0xFFFFFFFFL; + + // 2^224 - 2^96 + 1 + static final int[] P = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, + 0xFFFFFFFF, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0x00000000, + 0x00000000, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001 }; + private static final int P6 = 0xFFFFFFFF; + private static final int PExt13 = 0xFFFFFFFF; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat224.add(x, y, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(14, xx, yy, zz); + if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(14, zz, PExtInv.length); + } + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(7, x, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat224.fromBigInteger(x); + if (z[6] == P6 && Nat224.gte(z, P)) + { + Nat224.subFrom(P, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(7, x, 0, z); + } + else + { + int c = Nat224.add(x, P, z); + Nat.shiftDownBit(7, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat224.createExt(); + Nat224.mul(x, y, tt); + reduce(tt, z); + } + + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat224.mulAddTo(x, y, zz); + if (c != 0 || (zz[13] == PExt13 && Nat.gte(14, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(14, zz, PExtInv.length); + } + } + } + + public static void negate(int[] x, int[] z) + { + if (Nat224.isZero(x)) + { + Nat224.zero(z); + } + else + { + Nat224.sub(P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long xx10 = xx[10] & M, xx11 = xx[11] & M, xx12 = xx[12] & M, xx13 = xx[13] & M; + + final long n = 1; + + long t0 = (xx[7] & M) + xx11 - n; + long t1 = (xx[8] & M) + xx12; + long t2 = (xx[9] & M) + xx13; + + long cc = 0; + cc += (xx[0] & M) - t0; + long z0 = cc & M; + cc >>= 32; + cc += (xx[1] & M) - t1; + z[1] = (int)cc; + cc >>= 32; + cc += (xx[2] & M) - t2; + z[2] = (int)cc; + cc >>= 32; + cc += (xx[3] & M) + t0 - xx10; + long z3 = cc & M; + cc >>= 32; + cc += (xx[4] & M) + t1 - xx11; + z[4] = (int)cc; + cc >>= 32; + cc += (xx[5] & M) + t2 - xx12; + z[5] = (int)cc; + cc >>= 32; + cc += (xx[6] & M) + xx10 - xx13; + z[6] = (int)cc; + cc >>= 32; + cc += n; + +// assert cc >= 0; + + z3 += cc; + + z0 -= cc; + z[0] = (int)z0; + cc = z0 >> 32; + if (cc != 0) + { + cc += (z[1] & M); + z[1] = (int)cc; + cc >>= 32; + cc += (z[2] & M); + z[2] = (int)cc; + z3 += cc >> 32; + } + z[3] = (int)z3; + cc = z3 >> 32; + +// assert cc == 0 || cc == 1; + + if ((cc != 0 && Nat.incAt(7, z, 4) != 0) + || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void reduce32(int x, int[] z) + { + long cc = 0; + + if (x != 0) + { + long xx07 = x & M; + + cc += (z[0] & M) - xx07; + z[0] = (int)cc; + cc >>= 32; + if (cc != 0) + { + cc += (z[1] & M); + z[1] = (int)cc; + cc >>= 32; + cc += (z[2] & M); + z[2] = (int)cc; + cc >>= 32; + } + cc += (z[3] & M) + xx07; + z[3] = (int)cc; + cc >>= 32; + +// assert cc == 0 || cc == 1; + } + + if ((cc != 0 && Nat.incAt(7, z, 4) != 0) + || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat224.createExt(); + Nat224.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat224.createExt(); + Nat224.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat224.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat224.sub(x, y, z); + if (c != 0) + { + subPInvFrom(z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(14, xx, yy, zz); + if (c != 0) + { + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(14, zz, PExtInv.length); + } + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(7, x, 0, z); + if (c != 0 || (z[6] == P6 && Nat224.gte(z, P))) + { + addPInvTo(z); + } + } + + private static void addPInvTo(int[] z) + { + long c = (z[0] & M) - 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) + 1; + z[3] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.incAt(7, z, 4); + } + } + + private static void subPInvFrom(int[] z) + { + long c = (z[0] & M) + 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) - 1; + z[3] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.decAt(7, z, 4); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java new file mode 100644 index 00000000..90e03de3 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java @@ -0,0 +1,272 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.Mod; +import org.bouncycastle.math.ec.Nat; +import org.bouncycastle.util.Arrays; + +public class SecP224R1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP224R1Curve.q; + + protected int[] x; + + public SecP224R1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP224R1FieldElement"); + } + + this.x = SecP224R1Field.fromBigInteger(x); + } + + public SecP224R1FieldElement() + { + this.x = Nat224.create(); + } + + protected SecP224R1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat224.isZero(x); + } + + public boolean isOne() + { + return Nat224.isOne(x); + } + + public boolean testBitZero() + { + return Nat224.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat224.toBigInteger(x); + } + + public String getFieldName() + { + return "SecP224R1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224R1Field.add(x, ((SecP224R1FieldElement)b).x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat224.create(); + SecP224R1Field.addOne(x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224R1Field.subtract(x, ((SecP224R1FieldElement)b).x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat224.create(); + SecP224R1Field.multiply(x, ((SecP224R1FieldElement)b).x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat224.create(); + Mod.invert(SecP224R1Field.P, ((SecP224R1FieldElement)b).x, z); + SecP224R1Field.multiply(z, x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat224.create(); + SecP224R1Field.negate(x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat224.create(); + SecP224R1Field.square(x, z); + return new SecP224R1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP224R1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat224.create(); + Mod.invert(SecP224R1Field.P, x, z); + return new SecP224R1FieldElement(z); + } + + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + int[] c = this.x; + if (Nat224.isZero(c) || Nat224.isOne(c)) + { + return this; + } + + int[] nc = Nat224.create(); + SecP224R1Field.negate(c, nc); + + int[] r = Mod.random(SecP224R1Field.P); + int[] t = Nat224.create(); + + if (!isSquare(c)) + { + return null; + } + + while (!trySqrt(nc, r, t)) + { + SecP224R1Field.addOne(r, r); + } + + SecP224R1Field.square(t, r); + + return Nat224.eq(c, r) ? new SecP224R1FieldElement(t) : null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP224R1FieldElement)) + { + return false; + } + + SecP224R1FieldElement o = (SecP224R1FieldElement)other; + return Nat224.eq(x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 7); + } + + private static boolean isSquare(int[] x) + { + int[] t1 = Nat224.create(); + int[] t2 = Nat224.create(); + Nat224.copy(x, t1); + + for (int i = 0; i < 7; ++i) + { + Nat224.copy(t1, t2); + SecP224R1Field.squareN(t1, 1 << i, t1); + SecP224R1Field.multiply(t1, t2, t1); + } + + SecP224R1Field.squareN(t1, 95, t1); + return Nat224.isOne(t1); + } + + private static void RM(int[] nc, int[] d0, int[] e0, int[] d1, int[] e1, int[] f1, int[] t) + { + SecP224R1Field.multiply(e1, e0, t); + SecP224R1Field.multiply(t, nc, t); + SecP224R1Field.multiply(d1, d0, f1); + SecP224R1Field.add(f1, t, f1); + SecP224R1Field.multiply(d1, e0, t); + Nat224.copy(f1, d1); + SecP224R1Field.multiply(e1, d0, e1); + SecP224R1Field.add(e1, t, e1); + SecP224R1Field.square(e1, f1); + SecP224R1Field.multiply(f1, nc, f1); + } + + private static void RP(int[] nc, int[] d1, int[] e1, int[] f1, int[] t) + { + Nat224.copy(nc, f1); + + int[] d0 = Nat224.create(); + int[] e0 = Nat224.create(); + + for (int i = 0; i < 7; ++i) + { + Nat224.copy(d1, d0); + Nat224.copy(e1, e0); + + int j = 1 << i; + while (--j >= 0) + { + RS(d1, e1, f1, t); + } + + RM(nc, d0, e0, d1, e1, f1, t); + } + } + + private static void RS(int[] d, int[] e, int[] f, int[] t) + { + SecP224R1Field.multiply(e, d, e); + SecP224R1Field.twice(e, e); + SecP224R1Field.square(d, t); + SecP224R1Field.add(f, t, d); + SecP224R1Field.multiply(f, t, f); + int c = Nat.shiftUpBits(7, f, 2, 0); + SecP224R1Field.reduce32(c, f); + } + + private static boolean trySqrt(int[] nc, int[] r, int[] t) + { + int[] d1 = Nat224.create(); + Nat224.copy(r, d1); + int[] e1 = Nat224.create(); + e1[0] = 1; + int[] f1 = Nat224.create(); + RP(nc, d1, e1, f1, t); + + int[] d0 = Nat224.create(); + int[] e0 = Nat224.create(); + + for (int k = 1; k < 96; ++k) + { + Nat224.copy(d1, d0); + Nat224.copy(e1, e0); + + RS(d1, e1, f1, t); + + if (Nat224.isZero(d1)) + { + Mod.invert(SecP224R1Field.P, e0, t); + SecP224R1Field.multiply(t, d0, t); + return true; + } + } + + return false; + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java new file mode 100644 index 00000000..8b4de02f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java @@ -0,0 +1,323 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.Nat; + +public class SecP224R1Point extends ECPoint +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP224R1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + protected boolean getCompressionYTilde() + { + return this.getAffineYCoord().testBitZero(); + } + + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Y1 = (SecP224R1FieldElement)this.y; + SecP224R1FieldElement X2 = (SecP224R1FieldElement)b.getXCoord(), Y2 = (SecP224R1FieldElement)b.getYCoord(); + + SecP224R1FieldElement Z1 = (SecP224R1FieldElement)this.zs[0]; + SecP224R1FieldElement Z2 = (SecP224R1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat224.createExt(); + int[] t2 = Nat224.create(); + int[] t3 = Nat224.create(); + int[] t4 = Nat224.create(); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP224R1Field.square(Z1.x, S2); + + U2 = t2; + SecP224R1Field.multiply(S2, X2.x, U2); + + SecP224R1Field.multiply(S2, Z1.x, S2); + SecP224R1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP224R1Field.square(Z2.x, S1); + + U1 = tt1; + SecP224R1Field.multiply(S1, X1.x, U1); + + SecP224R1Field.multiply(S1, Z2.x, S1); + SecP224R1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat224.create(); + SecP224R1Field.subtract(U1, U2, H); + + int[] R = t2; + SecP224R1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat224.isZero(H)) + { + if (Nat224.isZero(R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP224R1Field.square(H, HSquared); + + int[] G = Nat224.create(); + SecP224R1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP224R1Field.multiply(HSquared, U1, V); + + SecP224R1Field.negate(G, G); + Nat224.mul(S1, G, tt1); + + c = Nat224.addBothTo(V, V, G); + SecP224R1Field.reduce32(c, G); + + SecP224R1FieldElement X3 = new SecP224R1FieldElement(t4); + SecP224R1Field.square(R, X3.x); + SecP224R1Field.subtract(X3.x, G, X3.x); + + SecP224R1FieldElement Y3 = new SecP224R1FieldElement(G); + SecP224R1Field.subtract(V, X3.x, Y3.x); + SecP224R1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP224R1Field.reduce(tt1, Y3.x); + + SecP224R1FieldElement Z3 = new SecP224R1FieldElement(H); + if (!Z1IsOne) + { + SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP224R1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; + + return new SecP224R1Point(curve, X3, Y3, zs, this.withCompression); + } + + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP224R1FieldElement Y1 = (SecP224R1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP224R1FieldElement X1 = (SecP224R1FieldElement)this.x, Z1 = (SecP224R1FieldElement)this.zs[0]; + + int c; + int[] t1 = Nat224.create(); + int[] t2 = Nat224.create(); + + int[] Y1Squared = Nat224.create(); + SecP224R1Field.square(Y1.x, Y1Squared); + + int[] T = Nat224.create(); + SecP224R1Field.square(Y1Squared, T); + + boolean Z1IsOne = Z1.isOne(); + + int[] Z1Squared = Z1.x; + if (!Z1IsOne) + { + Z1Squared = t2; + SecP224R1Field.square(Z1.x, Z1Squared); + } + + SecP224R1Field.subtract(X1.x, Z1Squared, t1); + + int[] M = t2; + SecP224R1Field.add(X1.x, Z1Squared, M); + SecP224R1Field.multiply(M, t1, M); + c = Nat224.addBothTo(M, M, M); + SecP224R1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP224R1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(7, S, 2, 0); + SecP224R1Field.reduce32(c, S); + + c = Nat.shiftUpBits(7, T, 3, 0, t1); + SecP224R1Field.reduce32(c, t1); + + SecP224R1FieldElement X3 = new SecP224R1FieldElement(T); + SecP224R1Field.square(M, X3.x); + SecP224R1Field.subtract(X3.x, S, X3.x); + SecP224R1Field.subtract(X3.x, S, X3.x); + + SecP224R1FieldElement Y3 = new SecP224R1FieldElement(S); + SecP224R1Field.subtract(S, X3.x, Y3.x); + SecP224R1Field.multiply(Y3.x, M, Y3.x); + SecP224R1Field.subtract(Y3.x, t1, Y3.x); + + SecP224R1FieldElement Z3 = new SecP224R1FieldElement(M); + SecP224R1Field.twice(Y1.x, Z3.x); + if (!Z1IsOne) + { + SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP224R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + public ECPoint subtract(ECPoint b) + { + if (b.isInfinity()) + { + return this; + } + + // Add -b + return add(b.negate()); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP224R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java index 39c730d1..7977d9df 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java @@ -5,7 +5,11 @@ import java.math.BigInteger; import org.bouncycastle.math.ec.ECConstants; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECMultiplier; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.GLVMultiplier; +import org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism; +import org.bouncycastle.math.ec.endo.GLVTypeBParameters; import org.bouncycastle.math.field.FiniteFields; import org.bouncycastle.util.encoders.Hex; @@ -67,6 +71,11 @@ public class SecP256K1Curve extends ECCurve return new SecP256K1Point(this, x, y, withCompression); } + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP256K1Point(this, x, y, zs, withCompression); + } + protected ECPoint decompressPoint(int yTilde, BigInteger X1) { ECFieldElement x = fromBigInteger(X1); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java index 74313386..221f505c 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Field.java @@ -2,17 +2,20 @@ package org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import org.bouncycastle.math.ec.Nat; + public class SecP256K1Field { // 2^256 - 2^32 - 2^9 - 2^8 - 2^7 - 2^6 - 2^4 - 1 static final int[] P = new int[]{ 0xFFFFFC2F, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; - private static final int P7 = 0xFFFFFFFF; - private static final int[] PExt = new int[]{ 0x000E90A1, 0x000007A2, 0x00000001, 0x00000000, 0x00000000, + static final int[] PExt = new int[]{ 0x000E90A1, 0x000007A2, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFFF85E, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFFF16F5F, 0xFFFFF85D, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x000007A1, 0x00000002 }; + private static final int P7 = 0xFFFFFFFF; private static final int PExt15 = 0xFFFFFFFF; - private static final long PInv = 0x00000001000003D1L; private static final int PInv33 = 0x3D1; public static void add(int[] x, int[] y, int[] z) @@ -20,26 +23,28 @@ public class SecP256K1Field int c = Nat256.add(x, y, z); if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) { - Nat256.addDWord(PInv, z, 0); + Nat.add33To(8, PInv33, z); } } public static void addExt(int[] xx, int[] yy, int[] zz) { - int c = Nat256.addExt(xx, yy, zz); - if (c != 0 || (zz[15] == PExt15 && Nat256.gteExt(zz, PExt))) + int c = Nat.add(16, xx, yy, zz); + if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt))) { - Nat256.subExt(zz, PExt, zz); + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(16, zz, PExtInv.length); + } } } public static void addOne(int[] x, int[] z) { - System.arraycopy(x, 0, z, 0, 8); - int c = Nat256.inc(z, 0); + int c = Nat.inc(8, x, z); if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) { - Nat256.addDWord(PInv, z, 0); + Nat.add33To(8, PInv33, z); } } @@ -48,7 +53,7 @@ public class SecP256K1Field int[] z = Nat256.fromBigInteger(x); if (z[7] == P7 && Nat256.gte(z, P)) { - Nat256.addDWord(PInv, z, 0); + Nat256.subFrom(P, z); } return z; } @@ -57,12 +62,12 @@ public class SecP256K1Field { if ((x[0] & 1) == 0) { - Nat256.shiftDownBit(x, 0, z); + Nat.shiftDownBit(8, x, 0, z); } else { int c = Nat256.add(x, P, z); - Nat256.shiftDownBit(z, c, z); + Nat.shiftDownBit(8, z, c); } } @@ -73,6 +78,18 @@ public class SecP256K1Field reduce(tt, z); } + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat256.mulAddTo(x, y, zz); + if (c != 0 || (zz[15] == PExt15 && Nat.gte(16, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(16, zz, PExtInv.length); + } + } + } + public static void negate(int[] x, int[] z) { if (Nat256.isZero(x)) @@ -87,14 +104,23 @@ public class SecP256K1Field public static void reduce(int[] xx, int[] z) { - long c = Nat256.mul33AddExt(PInv33, xx, 8, xx, 0, z, 0); - c = Nat256.mul33DWordAdd(PInv33, c, z, 0); + long cc = Nat256.mul33Add(PInv33, xx, 8, xx, 0, z, 0); + int c = Nat256.mul33DWordAdd(PInv33, cc, z, 0); // assert c == 0L || c == 1L; if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) { - Nat256.addDWord(PInv, z, 0); + Nat.add33To(8, PInv33, z); + } + } + + public static void reduce32(int x, int[] z) + { + if ((x != 0 && Nat256.mul33WordAdd(PInv33, x, z, 0) != 0) + || (z[7] == P7 && Nat256.gte(z, P))) + { + Nat.add33To(8, PInv33, z); } } @@ -125,25 +151,28 @@ public class SecP256K1Field int c = Nat256.sub(x, y, z); if (c != 0) { - Nat256.subDWord(PInv, z); + Nat.sub33From(8, PInv33, z); } } public static void subtractExt(int[] xx, int[] yy, int[] zz) { - int c = Nat256.subExt(xx, yy, zz); + int c = Nat.sub(16, xx, yy, zz); if (c != 0) { - Nat256.addExt(zz, PExt, zz); + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(16, zz, PExtInv.length); + } } } public static void twice(int[] x, int[] z) { - int c = Nat256.shiftUpBit(x, 0, z); + int c = Nat.shiftUpBit(8, x, 0, z); if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) { - Nat256.addDWord(PInv, z, 0); + Nat.add33To(8, PInv33, z); } } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java index 0a874767..4454ef70 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java @@ -188,7 +188,7 @@ public class SecP256K1FieldElement extends ECFieldElement int[] t2 = x2; SecP256K1Field.square(t1, t2); - return Arrays.areEqual(x1, t2) ? new SecP256K1FieldElement(t1) : null; + return Nat256.eq(x1, t2) ? new SecP256K1FieldElement(t1) : null; } public boolean equals(Object other) @@ -204,11 +204,11 @@ public class SecP256K1FieldElement extends ECFieldElement } SecP256K1FieldElement o = (SecP256K1FieldElement)other; - return Arrays.areEqual(x, o.x); + return Nat256.eq(x, o.x); } public int hashCode() { - return Q.hashCode() ^ Arrays.hashCode(x); + return Q.hashCode() ^ Arrays.hashCode(x, 0, 8); } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java index f1d07cad..9557cb26 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java @@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.Nat; public class SecP256K1Point extends ECPoint { @@ -92,8 +93,9 @@ public class SecP256K1Point extends ECPoint SecP256K1FieldElement Z1 = (SecP256K1FieldElement)this.zs[0]; SecP256K1FieldElement Z2 = (SecP256K1FieldElement)b.getZCoord(0); + int c; int[] tt1 = Nat256.createExt(); - int[] tt2 = Nat256.createExt(); + int[] t2 = Nat256.create(); int[] t3 = Nat256.create(); int[] t4 = Nat256.create(); @@ -109,7 +111,7 @@ public class SecP256K1Point extends ECPoint S2 = t3; SecP256K1Field.square(Z1.x, S2); - U2 = tt2; + U2 = t2; SecP256K1Field.multiply(S2, X2.x, U2); SecP256K1Field.multiply(S2, Z1.x, S2); @@ -138,7 +140,7 @@ public class SecP256K1Point extends ECPoint int[] H = Nat256.create(); SecP256K1Field.subtract(U1, U2, H); - int[] R = tt2; + int[] R = t2; SecP256K1Field.subtract(S1, S2, R); // Check if b == this or b == -this @@ -163,19 +165,20 @@ public class SecP256K1Point extends ECPoint int[] V = t3; SecP256K1Field.multiply(HSquared, U1, V); + SecP256K1Field.negate(G, G); Nat256.mul(S1, G, tt1); + c = Nat256.addBothTo(V, V, G); + SecP256K1Field.reduce32(c, G); + SecP256K1FieldElement X3 = new SecP256K1FieldElement(t4); SecP256K1Field.square(R, X3.x); - SecP256K1Field.add(X3.x, G, X3.x); - SecP256K1Field.subtract(X3.x, V, X3.x); - SecP256K1Field.subtract(X3.x, V, X3.x); + SecP256K1Field.subtract(X3.x, G, X3.x); SecP256K1FieldElement Y3 = new SecP256K1FieldElement(G); SecP256K1Field.subtract(V, X3.x, Y3.x); - Nat256.mul(Y3.x, R, tt2); - SecP256K1Field.subtractExt(tt2, tt1, tt2); - SecP256K1Field.reduce(tt2, Y3.x); + SecP256K1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP256K1Field.reduce(tt1, Y3.x); SecP256K1FieldElement Z3 = new SecP256K1FieldElement(H); if (!Z1IsOne) @@ -210,27 +213,27 @@ public class SecP256K1Point extends ECPoint SecP256K1FieldElement X1 = (SecP256K1FieldElement)this.x, Z1 = (SecP256K1FieldElement)this.zs[0]; + int c; + int[] Y1Squared = Nat256.create(); SecP256K1Field.square(Y1.x, Y1Squared); int[] T = Nat256.create(); SecP256K1Field.square(Y1Squared, T); - int[] t1 = Nat256.create(); - SecP256K1Field.square(X1.x, t1); - int[] M = Nat256.create(); - SecP256K1Field.twice(t1, M); - SecP256K1Field.add(M, t1, M); + SecP256K1Field.square(X1.x, M); + c = Nat256.addBothTo(M, M, M); + SecP256K1Field.reduce32(c, M); int[] S = Y1Squared; SecP256K1Field.multiply(Y1Squared, X1.x, S); - SecP256K1Field.twice(S, S); - SecP256K1Field.twice(S, S); + c = Nat.shiftUpBits(8, S, 2, 0); + SecP256K1Field.reduce32(c, S); - SecP256K1Field.twice(T, t1); - SecP256K1Field.twice(t1, t1); - SecP256K1Field.twice(t1, t1); + int[] t1 = Nat256.create(); + c = Nat.shiftUpBits(8, T, 3, 0, t1); + SecP256K1Field.reduce32(c, t1); SecP256K1FieldElement X3 = new SecP256K1FieldElement(T); SecP256K1Field.square(M, X3.x); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java index f27ac876..ae3bfacb 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java @@ -69,6 +69,11 @@ public class SecP256R1Curve extends ECCurve return new SecP256R1Point(this, x, y, withCompression); } + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP256R1Point(this, x, y, zs, withCompression); + } + protected ECPoint decompressPoint(int yTilde, BigInteger X1) { ECFieldElement x = fromBigInteger(X1); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java index 21ecc226..479f62e7 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Field.java @@ -2,6 +2,8 @@ package org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import org.bouncycastle.math.ec.Nat; + public class SecP256R1Field { private static final long M = 0xFFFFFFFFL; @@ -9,36 +11,36 @@ public class SecP256R1Field // 2^256 - 2^224 + 2^192 + 2^96 - 1 static final int[] P = new int[]{ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0xFFFFFFFF }; - private static final int P7 = 0xFFFFFFFF; - private static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, + static final int[] PExt = new int[]{ 0x00000001, 0x00000000, 0x00000000, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0xFFFFFFFE, 0x00000001, 0x00000001, 0xFFFFFFFE, 0x00000002, 0xFFFFFFFE }; + private static final int P7 = 0xFFFFFFFF; + private static final int PExt15 = 0xFFFFFFFF; public static void add(int[] x, int[] y, int[] z) { int c = Nat256.add(x, y, z); if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) { - Nat256.sub(z, P, z); + addPInvTo(z); } } public static void addExt(int[] xx, int[] yy, int[] zz) { - int c = Nat256.addExt(xx, yy, zz); - if (c != 0 || Nat256.gteExt(zz, PExt)) + int c = Nat.add(16, xx, yy, zz); + if (c != 0 || ((zz[15] & PExt15) == PExt15 && Nat.gte(16, zz, PExt))) { - Nat256.subExt(zz, PExt, zz); + Nat.subFrom(16, PExt, zz); } } public static void addOne(int[] x, int[] z) { - System.arraycopy(x, 0, z, 0, 8); - int c = Nat256.inc(z, 0); + int c = Nat.inc(8, x, z); if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) { - Nat256.sub(z, P, z); + addPInvTo(z); } } @@ -47,7 +49,7 @@ public class SecP256R1Field int[] z = Nat256.fromBigInteger(x); if (z[7] == P7 && Nat256.gte(z, P)) { - Nat256.sub(z, P, z); + Nat256.subFrom(P, z); } return z; } @@ -56,12 +58,12 @@ public class SecP256R1Field { if ((x[0] & 1) == 0) { - Nat256.shiftDownBit(x, 0, z); + Nat.shiftDownBit(8, x, 0, z); } else { int c = Nat256.add(x, P, z); - Nat256.shiftDownBit(z, c, z); + Nat.shiftDownBit(8, z, c); } } @@ -72,6 +74,15 @@ public class SecP256R1Field reduce(tt, z); } + public static void multiplyAddToExt(int[] x, int[] y, int[] zz) + { + int c = Nat256.mulAddTo(x, y, zz); + if (c != 0 || ((zz[15] & PExt15) == PExt15 && Nat.gte(16, zz, PExt))) + { + Nat.subFrom(16, PExt, zz); + } + } + public static void negate(int[] x, int[] z) { if (Nat256.isZero(x)) @@ -89,9 +100,13 @@ public class SecP256R1Field long xx08 = xx[8] & M, xx09 = xx[9] & M, xx10 = xx[10] & M, xx11 = xx[11] & M; long xx12 = xx[12] & M, xx13 = xx[13] & M, xx14 = xx[14] & M, xx15 = xx[15] & M; + final long n = 6; + + xx08 -= n; + long t0 = xx08 + xx09; long t1 = xx09 + xx10; - long t2 = xx10 + xx11; + long t2 = xx10 + xx11 - xx15; long t3 = xx11 + xx12; long t4 = xx12 + xx13; long t5 = xx13 + xx14; @@ -104,7 +119,7 @@ public class SecP256R1Field cc += (xx[1] & M) + t1 - t4 - t6; z[1] = (int)cc; cc >>= 32; - cc += (xx[2] & M) + t2 - t5 - xx15; + cc += (xx[2] & M) + t2 - t5; z[2] = (int)cc; cc >>= 32; cc += (xx[3] & M) + (t3 << 1) + xx13 - xx15 - t0; @@ -113,36 +128,67 @@ public class SecP256R1Field cc += (xx[4] & M) + (t4 << 1) + xx14 - t1; z[4] = (int)cc; cc >>= 32; - cc += (xx[5] & M) + (t5 << 1) + xx15 - t2; + cc += (xx[5] & M) + (t5 << 1) - t2; z[5] = (int)cc; cc >>= 32; cc += (xx[6] & M) + (t6 << 1) + t5 - t0; z[6] = (int)cc; cc >>= 32; - cc += (xx[7] & M) + (xx15 << 1) + xx15 + xx08 - t2 - t4; + cc += (xx[7] & M) + (xx15 << 1) + xx08 - t2 - t4; z[7] = (int)cc; cc >>= 32; + cc += n; + +// assert cc >= 0; - int c = (int)cc; - if (c < 0) + reduce32((int)cc, z); + } + + public static void reduce32(int x, int[] z) + { + long cc = 0; + + if (x != 0) { - do + long xx08 = x & M; + + cc += (z[0] & M) + xx08; + z[0] = (int)cc; + cc >>= 32; + if (cc != 0) { - c += Nat256.add(z, P, z); + cc += (z[1] & M); + z[1] = (int)cc; + cc >>= 32; + cc += (z[2] & M); + z[2] = (int)cc; + cc >>= 32; } - while (c < 0); - } - else - { - while (c > 0) + cc += (z[3] & M) - xx08; + z[3] = (int)cc; + cc >>= 32; + if (cc != 0) { - c += Nat256.sub(z, P, z); + cc += (z[4] & M); + z[4] = (int)cc; + cc >>= 32; + cc += (z[5] & M); + z[5] = (int)cc; + cc >>= 32; } + cc += (z[6] & M) - xx08; + z[6] = (int)cc; + cc >>= 32; + cc += (z[7] & M) + xx08; + z[7] = (int)cc; + cc >>= 32; - if (z[7] == P7 && Nat256.gte(z, P)) - { - Nat256.sub(z, P, z); - } +// assert cc == 0 || cc == 1; + } + + if (cc != 0 || (z[7] == P7 && Nat256.gte(z, P))) + { + addPInvTo(z); } } @@ -173,25 +219,93 @@ public class SecP256R1Field int c = Nat256.sub(x, y, z); if (c != 0) { - Nat256.add(z, P, z); + subPInvFrom(z); } } public static void subtractExt(int[] xx, int[] yy, int[] zz) { - int c = Nat256.subExt(xx, yy, zz); + int c = Nat.sub(16, xx, yy, zz); if (c != 0) { - Nat256.addExt(zz, PExt, zz); + Nat.addTo(16, PExt, zz); } } public static void twice(int[] x, int[] z) { - int c = Nat256.shiftUpBit(x, 0, z); + int c = Nat.shiftUpBit(8, x, 0, z); if (c != 0 || (z[7] == P7 && Nat256.gte(z, P))) { - Nat256.sub(z, P, z); + addPInvTo(z); + } + } + + private static void addPInvTo(int[] z) + { + long c = (z[0] & M) + 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) - 1; + z[3] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M); + z[5] = (int)c; + c >>= 32; + } + c += (z[6] & M) - 1; + z[6] = (int)c; + c >>= 32; + c += (z[7] & M) + 1; + z[7] = (int)c; +// c >>= 32; + } + + private static void subPInvFrom(int[] z) + { + long c = (z[0] & M) - 1; + z[0] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[1] & M); + z[1] = (int)c; + c >>= 32; + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) + 1; + z[3] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[4] & M); + z[4] = (int)c; + c >>= 32; + c += (z[5] & M); + z[5] = (int)c; + c >>= 32; } + c += (z[6] & M) + 1; + z[6] = (int)c; + c >>= 32; + c += (z[7] & M) - 1; + z[7] = (int)c; +// c >>= 32; } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java index b01a20d6..084c21d4 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java @@ -162,7 +162,7 @@ public class SecP256R1FieldElement extends ECFieldElement SecP256R1Field.squareN(t1, 94, t1); SecP256R1Field.square(t1, t2); - return Arrays.areEqual(x1, t2) ? new SecP256R1FieldElement(t1) : null; + return Nat256.eq(x1, t2) ? new SecP256R1FieldElement(t1) : null; } public boolean equals(Object other) @@ -178,11 +178,11 @@ public class SecP256R1FieldElement extends ECFieldElement } SecP256R1FieldElement o = (SecP256R1FieldElement)other; - return Arrays.areEqual(x, o.x); + return Nat256.eq(x, o.x); } public int hashCode() { - return Q.hashCode() ^ Arrays.hashCode(x); + return Q.hashCode() ^ Arrays.hashCode(x, 0, 8); } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java index fe971c27..46683151 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java @@ -3,6 +3,7 @@ package org.bouncycastle.math.ec.custom.sec; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECFieldElement; import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.Nat; public class SecP256R1Point extends ECPoint { @@ -90,8 +91,9 @@ public class SecP256R1Point extends ECPoint SecP256R1FieldElement Z1 = (SecP256R1FieldElement)this.zs[0]; SecP256R1FieldElement Z2 = (SecP256R1FieldElement)b.getZCoord(0); + int c; int[] tt1 = Nat256.createExt(); - int[] tt2 = Nat256.createExt(); + int[] t2 = Nat256.create(); int[] t3 = Nat256.create(); int[] t4 = Nat256.create(); @@ -107,7 +109,7 @@ public class SecP256R1Point extends ECPoint S2 = t3; SecP256R1Field.square(Z1.x, S2); - U2 = tt2; + U2 = t2; SecP256R1Field.multiply(S2, X2.x, U2); SecP256R1Field.multiply(S2, Z1.x, S2); @@ -136,7 +138,7 @@ public class SecP256R1Point extends ECPoint int[] H = Nat256.create(); SecP256R1Field.subtract(U1, U2, H); - int[] R = tt2; + int[] R = t2; SecP256R1Field.subtract(S1, S2, R); // Check if b == this or b == -this @@ -161,19 +163,20 @@ public class SecP256R1Point extends ECPoint int[] V = t3; SecP256R1Field.multiply(HSquared, U1, V); + SecP256R1Field.negate(G, G); Nat256.mul(S1, G, tt1); + c = Nat256.addBothTo(V, V, G); + SecP256R1Field.reduce32(c, G); + SecP256R1FieldElement X3 = new SecP256R1FieldElement(t4); SecP256R1Field.square(R, X3.x); - SecP256R1Field.add(X3.x, G, X3.x); - SecP256R1Field.subtract(X3.x, V, X3.x); - SecP256R1Field.subtract(X3.x, V, X3.x); + SecP256R1Field.subtract(X3.x, G, X3.x); SecP256R1FieldElement Y3 = new SecP256R1FieldElement(G); SecP256R1Field.subtract(V, X3.x, Y3.x); - Nat256.mul(Y3.x, R, tt2); - SecP256R1Field.subtractExt(tt2, tt1, tt2); - SecP256R1Field.reduce(tt2, Y3.x); + SecP256R1Field.multiplyAddToExt(Y3.x, R, tt1); + SecP256R1Field.reduce(tt1, Y3.x); SecP256R1FieldElement Z3 = new SecP256R1FieldElement(H); if (!Z1IsOne) @@ -207,6 +210,7 @@ public class SecP256R1Point extends ECPoint SecP256R1FieldElement X1 = (SecP256R1FieldElement)this.x, Z1 = (SecP256R1FieldElement)this.zs[0]; + int c; int[] t1 = Nat256.create(); int[] t2 = Nat256.create(); @@ -230,17 +234,16 @@ public class SecP256R1Point extends ECPoint int[] M = t2; SecP256R1Field.add(X1.x, Z1Squared, M); SecP256R1Field.multiply(M, t1, M); - SecP256R1Field.twice(M, t1); - SecP256R1Field.add(M, t1, M); + c = Nat256.addBothTo(M, M, M); + SecP256R1Field.reduce32(c, M); int[] S = Y1Squared; SecP256R1Field.multiply(Y1Squared, X1.x, S); - SecP256R1Field.twice(S, S); - SecP256R1Field.twice(S, S); + c = Nat.shiftUpBits(8, S, 2, 0); + SecP256R1Field.reduce32(c, S); - SecP256R1Field.twice(T, t1); - SecP256R1Field.twice(t1, t1); - SecP256R1Field.twice(t1, t1); + c = Nat.shiftUpBits(8, T, 3, 0, t1); + SecP256R1Field.reduce32(c, t1); SecP256R1FieldElement X3 = new SecP256R1FieldElement(T); SecP256R1Field.square(M, X3.x); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java new file mode 100644 index 00000000..ad37b0cd --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java @@ -0,0 +1,105 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.field.FiniteFields; +import org.bouncycastle.util.encoders.Hex; + +public class SecP384R1Curve extends ECCurve +{ + public static final BigInteger q = new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF")); + + private static final int SecP384R1_DEFAULT_COORDS = COORD_JACOBIAN; + + protected SecP384R1Point infinity; + + public SecP384R1Curve() + { + super(FiniteFields.getPrimeField(q)); + + this.infinity = new SecP384R1Point(this, null, null); + + this.a = fromBigInteger(new BigInteger(1, + Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"))); + this.b = fromBigInteger(new BigInteger(1, + Hex.decode("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"))); + this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973")); + this.cofactor = BigInteger.valueOf(1); + + this.coord = SecP384R1_DEFAULT_COORDS; + } + + protected ECCurve cloneCurve() + { + return new SecP384R1Curve(); + } + + public boolean supportsCoordinateSystem(int coord) + { + switch (coord) + { + case COORD_JACOBIAN: + return true; + default: + return false; + } + } + + public BigInteger getQ() + { + return q; + } + + public int getFieldSize() + { + return q.bitLength(); + } + + public ECFieldElement fromBigInteger(BigInteger x) + { + return new SecP384R1FieldElement(x); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + { + return new SecP384R1Point(this, x, y, withCompression); + } + + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP384R1Point(this, x, y, zs, withCompression); + } + + protected ECPoint decompressPoint(int yTilde, BigInteger X1) + { + ECFieldElement x = fromBigInteger(X1); + ECFieldElement alpha = x.square().add(getA()).multiply(x).add(getB()); + ECFieldElement beta = alpha.sqrt(); + + // + // if we can't find a sqrt we haven't got a point on the + // curve - run! + // + if (beta == null) + { + throw new RuntimeException("Invalid point compression"); + } + + if (beta.testBitZero() != (yTilde == 1)) + { + // Use the other root + beta = beta.negate(); + } + + return new SecP384R1Point(this, x, beta, true); + } + + public ECPoint getInfinity() + { + return infinity; + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java new file mode 100644 index 00000000..82c9aa0a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Field.java @@ -0,0 +1,294 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.Nat; + +public class SecP384R1Field +{ + private static final long M = 0xFFFFFFFFL; + + // 2^384 - 2^128 - 2^96 + 2^32 - 1 + static final int[] P = new int[]{ 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + static final int[] PExt = new int[]{ 0x00000001, 0xFFFFFFFE, 0x00000000, 0x00000002, 0x00000000, 0xFFFFFFFE, + 0x00000000, 0x00000002, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0xFFFFFFFE, 0x00000001, 0x00000000, + 0xFFFFFFFE, 0xFFFFFFFD, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + private static final int[] PExtInv = new int[]{ 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFF, 0x00000001, + 0xFFFFFFFF, 0xFFFFFFFD, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFE, 0xFFFFFFFF, + 0x00000001, 0x00000002 }; + private static final int P11 = 0xFFFFFFFF; + private static final int PExt23 = 0xFFFFFFFF; + + public static void add(int[] x, int[] y, int[] z) + { + int c = Nat.add(12, x, y, z); + if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P))) + { + addPInvTo(z); + } + } + + public static void addExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.add(24, xx, yy, zz); + if (c != 0 || (zz[23] == PExt23 && Nat.gte(24, zz, PExt))) + { + if (Nat.addTo(PExtInv.length, PExtInv, zz) != 0) + { + Nat.incAt(24, zz, PExtInv.length); + } + } + } + + public static void addOne(int[] x, int[] z) + { + int c = Nat.inc(12, x, z); + if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P))) + { + addPInvTo(z); + } + } + + public static int[] fromBigInteger(BigInteger x) + { + int[] z = Nat.fromBigInteger(384, x); + if (z[11] == P11 && Nat.gte(12, z, P)) + { + Nat.subFrom(12, P, z); + } + return z; + } + + public static void half(int[] x, int[] z) + { + if ((x[0] & 1) == 0) + { + Nat.shiftDownBit(12, x, 0, z); + } + else + { + int c = Nat.add(12, x, P, z); + Nat.shiftDownBit(12, z, c); + } + } + + public static void multiply(int[] x, int[] y, int[] z) + { + int[] tt = Nat.create(24); + Nat384.mul(x, y, tt); + reduce(tt, z); + } + + public static void negate(int[] x, int[] z) + { + if (Nat.isZero(12, x)) + { + Nat.zero(12, z); + } + else + { + Nat.sub(12, P, x, z); + } + } + + public static void reduce(int[] xx, int[] z) + { + long xx16 = xx[16] & M, xx17 = xx[17] & M, xx18 = xx[18] & M, xx19 = xx[19] & M; + long xx20 = xx[20] & M, xx21 = xx[21] & M, xx22 = xx[22] & M, xx23 = xx[23] & M; + + final long n = 1; + + long t0 = (xx[12] & M) + xx20 - n; + long t1 = (xx[13] & M) + xx22; + long t2 = (xx[14] & M) + xx22 + xx23; + long t3 = (xx[15] & M) + xx23; + long t4 = xx17 + xx21; + long t5 = xx21 - xx23; + long t6 = xx22 - xx23; + + long cc = 0; + cc += (xx[0] & M) + t0 + t5; + z[0] = (int)cc; + cc >>= 32; + cc += (xx[1] & M) + xx23 - t0 + t1; + z[1] = (int)cc; + cc >>= 32; + cc += (xx[2] & M) - xx21 - t1 + t2; + z[2] = (int)cc; + cc >>= 32; + cc += (xx[3] & M) + t0 - t2 + t3 + t5; + z[3] = (int)cc; + cc >>= 32; + cc += (xx[4] & M) + xx16 + xx21 + t0 + t1 - t3 + t5; + z[4] = (int)cc; + cc >>= 32; + cc += (xx[5] & M) - xx16 + t1 + t2 + t4; + z[5] = (int)cc; + cc >>= 32; + cc += (xx[6] & M) + xx18 - xx17 + t2 + t3; + z[6] = (int)cc; + cc >>= 32; + cc += (xx[7] & M) + xx16 + xx19 - xx18 + t3; + z[7] = (int)cc; + cc >>= 32; + cc += (xx[8] & M) + xx16 + xx17 + xx20 - xx19; + z[8] = (int)cc; + cc >>= 32; + cc += (xx[9] & M) + xx18 - xx20 + t4; + z[9] = (int)cc; + cc >>= 32; + cc += (xx[10] & M) + xx18 + xx19 - t5 + t6; + z[10] = (int)cc; + cc >>= 32; + cc += (xx[11] & M) + xx19 + xx20 - t6; + z[11] = (int)cc; + cc >>= 32; + cc += n; + +// assert cc >= 0; + + reduce32((int)cc, z); + } + + public static void reduce32(int x, int[] z) + { + long cc = 0; + + if (x != 0) + { + long xx12 = x & M; + + cc += (z[0] & M) + xx12; + z[0] = (int)cc; + cc >>= 32; + cc += (z[1] & M) - xx12; + z[1] = (int)cc; + cc >>= 32; + if (cc != 0) + { + cc += (z[2] & M); + z[2] = (int)cc; + cc >>= 32; + } + cc += (z[3] & M) + xx12; + z[3] = (int)cc; + cc >>= 32; + cc += (z[4] & M) + xx12; + z[4] = (int)cc; + cc >>= 32; + +// assert cc == 0 || cc == 1; + } + + if ((cc != 0 && Nat.incAt(12, z, 5) != 0) + || (z[11] == P11 && Nat.gte(12, z, P))) + { + addPInvTo(z); + } + } + + public static void square(int[] x, int[] z) + { + int[] tt = Nat.create(24); + Nat384.square(x, tt); + reduce(tt, z); + } + + public static void squareN(int[] x, int n, int[] z) + { +// assert n > 0; + + int[] tt = Nat.create(24); + Nat384.square(x, tt); + reduce(tt, z); + + while (--n > 0) + { + Nat384.square(z, tt); + reduce(tt, z); + } + } + + public static void subtract(int[] x, int[] y, int[] z) + { + int c = Nat.sub(12, x, y, z); + if (c != 0) + { + subPInvFrom(z); + } + } + + public static void subtractExt(int[] xx, int[] yy, int[] zz) + { + int c = Nat.sub(24, xx, yy, zz); + if (c != 0) + { + if (Nat.subFrom(PExtInv.length, PExtInv, zz) != 0) + { + Nat.decAt(24, zz, PExtInv.length); + } + } + } + + public static void twice(int[] x, int[] z) + { + int c = Nat.shiftUpBit(12, x, 0, z); + if (c != 0 || (z[11] == P11 && Nat.gte(12, z, P))) + { + addPInvTo(z); + } + } + + private static void addPInvTo(int[] z) + { + long c = (z[0] & M) + 1; + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) - 1; + z[1] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) + 1; + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) + 1; + z[4] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.incAt(12, z, 5); + } + } + + private static void subPInvFrom(int[] z) + { + long c = (z[0] & M) - 1; + z[0] = (int)c; + c >>= 32; + c += (z[1] & M) + 1; + z[1] = (int)c; + c >>= 32; + if (c != 0) + { + c += (z[2] & M); + z[2] = (int)c; + c >>= 32; + } + c += (z[3] & M) - 1; + z[3] = (int)c; + c >>= 32; + c += (z[4] & M) - 1; + z[4] = (int)c; + c >>= 32; + if (c != 0) + { + Nat.decAt(12, z, 5); + } + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java new file mode 100644 index 00000000..b1023190 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java @@ -0,0 +1,211 @@ +package org.bouncycastle.math.ec.custom.sec; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.Mod; +import org.bouncycastle.math.ec.Nat; +import org.bouncycastle.util.Arrays; + +public class SecP384R1FieldElement extends ECFieldElement +{ + public static final BigInteger Q = SecP384R1Curve.q; + + protected int[] x; + + public SecP384R1FieldElement(BigInteger x) + { + if (x == null || x.signum() < 0 || x.compareTo(Q) >= 0) + { + throw new IllegalArgumentException("x value invalid for SecP384R1FieldElement"); + } + + this.x = SecP384R1Field.fromBigInteger(x); + } + + public SecP384R1FieldElement() + { + this.x = Nat.create(12); + } + + protected SecP384R1FieldElement(int[] x) + { + this.x = x; + } + + public boolean isZero() + { + return Nat.isZero(12, x); + } + + public boolean isOne() + { + return Nat.isOne(12, x); + } + + public boolean testBitZero() + { + return Nat.getBit(x, 0) == 1; + } + + public BigInteger toBigInteger() + { + return Nat.toBigInteger(12, x); + } + + public String getFieldName() + { + return "SecP384R1Field"; + } + + public int getFieldSize() + { + return Q.bitLength(); + } + + public ECFieldElement add(ECFieldElement b) + { + int[] z = Nat.create(12); + SecP384R1Field.add(x, ((SecP384R1FieldElement)b).x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement addOne() + { + int[] z = Nat.create(12); + SecP384R1Field.addOne(x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement subtract(ECFieldElement b) + { + int[] z = Nat.create(12); + SecP384R1Field.subtract(x, ((SecP384R1FieldElement)b).x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement multiply(ECFieldElement b) + { + int[] z = Nat.create(12); + SecP384R1Field.multiply(x, ((SecP384R1FieldElement)b).x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement divide(ECFieldElement b) + { +// return multiply(b.invert()); + int[] z = Nat.create(12); + Mod.invert(SecP384R1Field.P, ((SecP384R1FieldElement)b).x, z); + SecP384R1Field.multiply(z, x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement negate() + { + int[] z = Nat.create(12); + SecP384R1Field.negate(x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement square() + { + int[] z = Nat.create(12); + SecP384R1Field.square(x, z); + return new SecP384R1FieldElement(z); + } + + public ECFieldElement invert() + { +// return new SecP384R1FieldElement(toBigInteger().modInverse(Q)); + int[] z = Nat.create(12); + Mod.invert(SecP384R1Field.P, x, z); + return new SecP384R1FieldElement(z); + } + + /** + * return a sqrt root - the routine verifies that the calculation returns the right value - if + * none exists it returns null. + */ + public ECFieldElement sqrt() + { + // Raise this element to the exponent 2^382 - 2^126 - 2^94 + 2^30 + + int[] x1 = this.x; + if (Nat.isZero(12, x1) || Nat.isOne(12, x1)) + { + return this; + } + + int[] t1 = Nat.create(12); + int[] t2 = Nat.create(12); + int[] t3 = Nat.create(12); + int[] t4 = Nat.create(12); + + SecP384R1Field.square(x1, t1); + SecP384R1Field.multiply(t1, x1, t1); + + SecP384R1Field.squareN(t1, 2, t2); + SecP384R1Field.multiply(t2, t1, t2); + + SecP384R1Field.square(t2, t2); + SecP384R1Field.multiply(t2, x1, t2); + + SecP384R1Field.squareN(t2, 5, t3); + SecP384R1Field.multiply(t3, t2, t3); + + SecP384R1Field.squareN(t3, 5, t4); + SecP384R1Field.multiply(t4, t2, t4); + + SecP384R1Field.squareN(t4, 15, t2); + SecP384R1Field.multiply(t2, t4, t2); + + SecP384R1Field.squareN(t2, 2, t3); + SecP384R1Field.multiply(t1, t3, t1); + + SecP384R1Field.squareN(t3, 28, t3); + SecP384R1Field.multiply(t2, t3, t2); + + SecP384R1Field.squareN(t2, 60, t3); + SecP384R1Field.multiply(t3, t2, t3); + + int[] r = t2; + + SecP384R1Field.squareN(t3, 120, r); + SecP384R1Field.multiply(r, t3, r); + + SecP384R1Field.squareN(r, 15, r); + SecP384R1Field.multiply(r, t4, r); + + SecP384R1Field.squareN(r, 33, r); + SecP384R1Field.multiply(r, t1, r); + + SecP384R1Field.squareN(r, 64, r); + SecP384R1Field.multiply(r, x1, r); + + SecP384R1Field.squareN(r, 30, t1); + SecP384R1Field.square(t1, t2); + + return Nat.eq(12, x1, t2) ? new SecP384R1FieldElement(t1) : null; + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + + if (!(other instanceof SecP384R1FieldElement)) + { + return false; + } + + SecP384R1FieldElement o = (SecP384R1FieldElement)other; + return Nat.eq(12, x, o.x); + } + + public int hashCode() + { + return Q.hashCode() ^ Arrays.hashCode(x, 0, 12); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java new file mode 100644 index 00000000..f1d79303 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java @@ -0,0 +1,324 @@ +package org.bouncycastle.math.ec.custom.sec; + +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.math.ec.Nat; + +public class SecP384R1Point extends ECPoint +{ + /** + * Create a point which encodes with point compression. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * + * @deprecated Use ECCurve.createPoint to construct points + */ + public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) + { + this(curve, x, y, false); + } + + /** + * Create a point that encodes with or without point compresion. + * + * @param curve + * the curve to use + * @param x + * affine x co-ordinate + * @param y + * affine y co-ordinate + * @param withCompression + * if true encode with point compression + * + * @deprecated per-point compression property will be removed, refer + * {@link #getEncoded(boolean)} + */ + public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + { + super(curve, x, y); + + if ((x == null) != (y == null)) + { + throw new IllegalArgumentException("Exactly one of the field elements is null"); + } + + this.withCompression = withCompression; + } + + SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + super(curve, x, y, zs); + + this.withCompression = withCompression; + } + + protected ECPoint detach() + { + return new SecP384R1Point(null, getAffineXCoord(), getAffineYCoord()); + } + + protected boolean getCompressionYTilde() + { + return this.getAffineYCoord().testBitZero(); + } + + public ECPoint add(ECPoint b) + { + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return this; + } + if (this == b) + { + return twice(); + } + + ECCurve curve = this.getCurve(); + + SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.x, Y1 = (SecP384R1FieldElement)this.y; + SecP384R1FieldElement X2 = (SecP384R1FieldElement)b.getXCoord(), Y2 = (SecP384R1FieldElement)b.getYCoord(); + + SecP384R1FieldElement Z1 = (SecP384R1FieldElement)this.zs[0]; + SecP384R1FieldElement Z2 = (SecP384R1FieldElement)b.getZCoord(0); + + int c; + int[] tt1 = Nat.create(24); + int[] tt2 = Nat.create(24); + int[] t3 = Nat.create(12); + int[] t4 = Nat.create(12); + + boolean Z1IsOne = Z1.isOne(); + int[] U2, S2; + if (Z1IsOne) + { + U2 = X2.x; + S2 = Y2.x; + } + else + { + S2 = t3; + SecP384R1Field.square(Z1.x, S2); + + U2 = tt2; + SecP384R1Field.multiply(S2, X2.x, U2); + + SecP384R1Field.multiply(S2, Z1.x, S2); + SecP384R1Field.multiply(S2, Y2.x, S2); + } + + boolean Z2IsOne = Z2.isOne(); + int[] U1, S1; + if (Z2IsOne) + { + U1 = X1.x; + S1 = Y1.x; + } + else + { + S1 = t4; + SecP384R1Field.square(Z2.x, S1); + + U1 = tt1; + SecP384R1Field.multiply(S1, X1.x, U1); + + SecP384R1Field.multiply(S1, Z2.x, S1); + SecP384R1Field.multiply(S1, Y1.x, S1); + } + + int[] H = Nat.create(12); + SecP384R1Field.subtract(U1, U2, H); + + int[] R = Nat.create(12); + SecP384R1Field.subtract(S1, S2, R); + + // Check if b == this or b == -this + if (Nat.isZero(12, H)) + { + if (Nat.isZero(12, R)) + { + // this == b, i.e. this must be doubled + return this.twice(); + } + + // this == -b, i.e. the result is the point at infinity + return curve.getInfinity(); + } + + int[] HSquared = t3; + SecP384R1Field.square(H, HSquared); + + int[] G = Nat.create(12); + SecP384R1Field.multiply(HSquared, H, G); + + int[] V = t3; + SecP384R1Field.multiply(HSquared, U1, V); + + SecP384R1Field.negate(G, G); + Nat384.mul(S1, G, tt1); + + c = Nat.addBothTo(12, V, V, G); + SecP384R1Field.reduce32(c, G); + + SecP384R1FieldElement X3 = new SecP384R1FieldElement(t4); + SecP384R1Field.square(R, X3.x); + SecP384R1Field.subtract(X3.x, G, X3.x); + + SecP384R1FieldElement Y3 = new SecP384R1FieldElement(G); + SecP384R1Field.subtract(V, X3.x, Y3.x); + Nat384.mul(Y3.x, R, tt2); + SecP384R1Field.addExt(tt1, tt2, tt1); + SecP384R1Field.reduce(tt1, Y3.x); + + SecP384R1FieldElement Z3 = new SecP384R1FieldElement(H); + if (!Z1IsOne) + { + SecP384R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + if (!Z2IsOne) + { + SecP384R1Field.multiply(Z3.x, Z2.x, Z3.x); + } + + ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; + + return new SecP384R1Point(curve, X3, Y3, zs, this.withCompression); + } + + public ECPoint twice() + { + if (this.isInfinity()) + { + return this; + } + + ECCurve curve = this.getCurve(); + + SecP384R1FieldElement Y1 = (SecP384R1FieldElement)this.y; + if (Y1.isZero()) + { + return curve.getInfinity(); + } + + SecP384R1FieldElement X1 = (SecP384R1FieldElement)this.x, Z1 = (SecP384R1FieldElement)this.zs[0]; + + int c; + int[] t1 = Nat.create(12); + int[] t2 = Nat.create(12); + + int[] Y1Squared = Nat.create(12); + SecP384R1Field.square(Y1.x, Y1Squared); + + int[] T = Nat.create(12); + SecP384R1Field.square(Y1Squared, T); + + boolean Z1IsOne = Z1.isOne(); + + int[] Z1Squared = Z1.x; + if (!Z1IsOne) + { + Z1Squared = t2; + SecP384R1Field.square(Z1.x, Z1Squared); + } + + SecP384R1Field.subtract(X1.x, Z1Squared, t1); + + int[] M = t2; + SecP384R1Field.add(X1.x, Z1Squared, M); + SecP384R1Field.multiply(M, t1, M); + c = Nat.addBothTo(12, M, M, M); + SecP384R1Field.reduce32(c, M); + + int[] S = Y1Squared; + SecP384R1Field.multiply(Y1Squared, X1.x, S); + c = Nat.shiftUpBits(12, S, 2, 0); + SecP384R1Field.reduce32(c, S); + + c = Nat.shiftUpBits(12, T, 3, 0, t1); + SecP384R1Field.reduce32(c, t1); + + SecP384R1FieldElement X3 = new SecP384R1FieldElement(T); + SecP384R1Field.square(M, X3.x); + SecP384R1Field.subtract(X3.x, S, X3.x); + SecP384R1Field.subtract(X3.x, S, X3.x); + + SecP384R1FieldElement Y3 = new SecP384R1FieldElement(S); + SecP384R1Field.subtract(S, X3.x, Y3.x); + SecP384R1Field.multiply(Y3.x, M, Y3.x); + SecP384R1Field.subtract(Y3.x, t1, Y3.x); + + SecP384R1FieldElement Z3 = new SecP384R1FieldElement(M); + SecP384R1Field.twice(Y1.x, Z3.x); + if (!Z1IsOne) + { + SecP384R1Field.multiply(Z3.x, Z1.x, Z3.x); + } + + return new SecP384R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + } + + public ECPoint twicePlus(ECPoint b) + { + if (this == b) + { + return threeTimes(); + } + if (this.isInfinity()) + { + return b; + } + if (b.isInfinity()) + { + return twice(); + } + + ECFieldElement Y1 = this.y; + if (Y1.isZero()) + { + return b; + } + + return twice().add(b); + } + + public ECPoint threeTimes() + { + if (this.isInfinity() || this.y.isZero()) + { + return this; + } + + // NOTE: Be careful about recursions between twicePlus and threeTimes + return twice().add(this); + } + + public ECPoint subtract(ECPoint b) + { + if (b.isInfinity()) + { + return this; + } + + // Add -b + return add(b.negate()); + } + + public ECPoint negate() + { + if (this.isInfinity()) + { + return this; + } + + return new SecP384R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java index b58e34b7..ea42b578 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java @@ -69,6 +69,11 @@ public class SecP521R1Curve extends ECCurve return new SecP521R1Point(this, x, y, withCompression); } + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + { + return new SecP521R1Point(this, x, y, zs, withCompression); + } + protected ECPoint decompressPoint(int yTilde, BigInteger X1) { ECFieldElement x = fromBigInteger(X1); diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java index 2d3c6ffa..33f4a342 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Field.java @@ -16,7 +16,7 @@ public class SecP521R1Field int c = Nat.add(16, x, y, z) + x[16] + y[16]; if (c > P16 || (c == P16 && Nat.eq(16, z, P))) { - c += Nat.inc(16, z, 0); + c += Nat.inc(16, z); c &= P16; } z[16] = c; @@ -24,11 +24,10 @@ public class SecP521R1Field public static void addOne(int[] x, int[] z) { - System.arraycopy(x, 0, z, 0, 16); - int c = Nat.inc(16, z, 0) + x[16]; + int c = Nat.inc(16, x, z) + x[16]; if (c > P16 || (c == P16 && Nat.eq(16, z, P))) { - c += Nat.inc(16, z, 0); + c += Nat.inc(16, z); c &= P16; } z[16] = c; @@ -75,12 +74,12 @@ public class SecP521R1Field // assert xx[32] >>> 18 == 0; int xx32 = xx[32]; - int c = Nat.shiftDownBits(16, xx, 16, 9, xx32, z) >>> 23; + int c = Nat.shiftDownBits(16, xx, 16, 9, xx32, z, 0) >>> 23; c += xx32 >>> 9; - c += Nat.add(16, z, xx, z); + c += Nat.addTo(16, xx, z); if (c > P16 || (c == P16 && Nat.eq(16, z, P))) { - c += Nat.inc(16, z, 0); + c += Nat.inc(16, z); c &= P16; } z[16] = c; @@ -89,10 +88,10 @@ public class SecP521R1Field public static void reduce23(int[] z) { int z16 = z[16]; - int c = Nat.addWord(16, z16 >>> 9, z) + (z16 & P16); + int c = Nat.addWordTo(16, z16 >>> 9, z) + (z16 & P16); if (c > P16 || (c == P16 && Nat.eq(16, z, P))) { - c += Nat.inc(16, z, 0); + c += Nat.inc(16, z); c &= P16; } z[16] = c; @@ -125,7 +124,7 @@ public class SecP521R1Field int c = Nat.sub(16, x, y, z) + x[16] - y[16]; if (c < 0) { - c += Nat.dec(16, z, 0); + c += Nat.dec(16, z); c &= P16; } z[16] = c; @@ -133,13 +132,9 @@ public class SecP521R1Field public static void twice(int[] x, int[] z) { - int c = Nat.shiftUpBit(16, x, 0, z) | (x[16] << 1); - if (c > P16 || (c == P16 && Nat.eq(16, z, P))) - { - c += Nat.inc(16, z, 0); - c &= P16; - } - z[16] = c; + int x16 = x[16]; + int c = Nat.shiftUpBit(16, x, x16 << 23, z) | (x16 << 1); + z[16] = c & P16; } protected static void implMultiply(int[] x, int[] y, int[] zz) @@ -155,6 +150,6 @@ public class SecP521R1Field Nat512.square(x, zz); int x16 = x[16]; - zz[32] = Nat.mulWordAdd(16, x16 << 1, x, zz, 16) + (x16 * x16); + zz[32] = Nat.mulWordAddTo(16, x16 << 1, x, 0, zz, 16) + (x16 * x16); } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java index 0a395a76..785abaa1 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java @@ -143,7 +143,7 @@ public class SecP521R1FieldElement extends ECFieldElement SecP521R1Field.squareN(x1, 519, t1); SecP521R1Field.square(t1, t2); - return Arrays.areEqual(x1, t2) ? new SecP521R1FieldElement(t1) : null; + return Nat.eq(17, x1, t2) ? new SecP521R1FieldElement(t1) : null; } public boolean equals(Object other) @@ -159,11 +159,11 @@ public class SecP521R1FieldElement extends ECFieldElement } SecP521R1FieldElement o = (SecP521R1FieldElement)other; - return Arrays.areEqual(x, o.x); + return Nat.eq(17, x, o.x); } public int hashCode() { - return Q.hashCode() ^ Arrays.hashCode(x); + return Q.hashCode() ^ Arrays.hashCode(x, 0, 17); } } diff --git a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java index 4b4e5b3b..12fcecda 100644 --- a/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java +++ b/core/src/main/java/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java @@ -230,8 +230,8 @@ public class SecP521R1Point extends ECPoint int[] M = t2; SecP521R1Field.add(X1.x, Z1Squared, M); SecP521R1Field.multiply(M, t1, M); - SecP521R1Field.twice(M, t1); - SecP521R1Field.add(M, t1, M); + Nat.addBothTo(17, M, M, M); + SecP521R1Field.reduce23(M); int[] S = Y1Squared; SecP521R1Field.multiply(Y1Squared, X1.x, S); diff --git a/core/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java b/core/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java new file mode 100644 index 00000000..2be0c01d --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/endo/ECEndomorphism.java @@ -0,0 +1,10 @@ +package org.bouncycastle.math.ec.endo; + +import org.bouncycastle.math.ec.ECPointMap; + +public interface ECEndomorphism +{ + ECPointMap getPointMap(); + + boolean hasEfficientPointMap(); +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java new file mode 100644 index 00000000..8897bb38 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVEndomorphism.java @@ -0,0 +1,8 @@ +package org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +public interface GLVEndomorphism extends ECEndomorphism +{ + BigInteger[] decomposeScalar(BigInteger k); +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java new file mode 100644 index 00000000..ab710d1a --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java @@ -0,0 +1,58 @@ +package org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECPointMap; +import org.bouncycastle.math.ec.ScaleXPointMap; + +public class GLVTypeBEndomorphism implements GLVEndomorphism +{ + protected final ECCurve curve; + protected final GLVTypeBParameters parameters; + protected final ECPointMap pointMap; + + public GLVTypeBEndomorphism(ECCurve curve, GLVTypeBParameters parameters) + { + this.curve = curve; + this.parameters = parameters; + this.pointMap = new ScaleXPointMap(curve.fromBigInteger(parameters.getBeta())); + } + + public BigInteger[] decomposeScalar(BigInteger k) + { + int bits = parameters.getBits(); + BigInteger b1 = calculateB(k, parameters.getG1(), bits); + BigInteger b2 = calculateB(k, parameters.getG2(), bits); + + BigInteger[] v1 = parameters.getV1(), v2 = parameters.getV2(); + BigInteger a = k.subtract((b1.multiply(v1[0])).add(b2.multiply(v2[0]))); + BigInteger b = (b1.multiply(v1[1])).add(b2.multiply(v2[1])).negate(); + + return new BigInteger[]{ a, b }; + } + + public ECPointMap getPointMap() + { + return pointMap; + } + + public boolean hasEfficientPointMap() + { + return true; + } + + protected BigInteger calculateB(BigInteger k, BigInteger g, int t) + { + boolean negative = (g.signum() < 0); + BigInteger b = k.multiply(g.abs()); + boolean extra = b.testBit(t - 1); + b = b.shiftRight(t); + if (extra) + { + b = b.add(ECConstants.ONE); + } + return negative ? b.negate() : b; + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java new file mode 100644 index 00000000..f02a882f --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java @@ -0,0 +1,59 @@ +package org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +public class GLVTypeBParameters +{ + protected final BigInteger beta; + protected final BigInteger lambda; + protected final BigInteger[] v1, v2; + protected final BigInteger g1, g2; + protected final int bits; + + public GLVTypeBParameters(BigInteger beta, BigInteger lambda, BigInteger[] v1, BigInteger[] v2, BigInteger g1, + BigInteger g2, int bits) + { + this.beta = beta; + this.lambda = lambda; + this.v1 = v1; + this.v2 = v2; + this.g1 = g1; + this.g2 = g2; + this.bits = bits; + } + + public BigInteger getBeta() + { + return beta; + } + + public BigInteger getLambda() + { + return lambda; + } + + public BigInteger[] getV1() + { + return v1; + } + + public BigInteger[] getV2() + { + return v2; + } + + public BigInteger getG1() + { + return g1; + } + + public BigInteger getG2() + { + return g2; + } + + public int getBits() + { + return bits; + } +} diff --git a/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java b/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java new file mode 100644 index 00000000..3b332978 --- /dev/null +++ b/core/src/main/java/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java @@ -0,0 +1,373 @@ +package org.bouncycastle.math.ec.tools; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import org.bouncycastle.asn1.x9.ECNamedCurveTable; +import org.bouncycastle.asn1.x9.X9ECParameters; +import org.bouncycastle.math.ec.ECAlgorithms; +import org.bouncycastle.math.ec.ECConstants; +import org.bouncycastle.math.ec.ECCurve; +import org.bouncycastle.math.ec.ECFieldElement; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.BigIntegers; + +public class DiscoverEndomorphisms +{ + private static final int radix = 16; + + public static void main(String[] args) + { + if (args.length < 1) + { + System.err.println("Expected a list of curve names as arguments"); + return; + } + + for (int i = 0; i < args.length; ++i) + { + discoverEndomorphism(args[i]); + } + } + + private static void discoverEndomorphism(String curveName) + { + X9ECParameters x9 = ECNamedCurveTable.getByName(curveName); + if (x9 == null) + { + System.err.println("Unknown curve: " + curveName); + return; + } + + ECCurve c = x9.getCurve(); + if (ECAlgorithms.isFpCurve(c)) + { + BigInteger characteristic = c.getField().getCharacteristic(); + + if (c.getA().isZero() && characteristic.mod(ECConstants.THREE).equals(ECConstants.ONE)) + { + System.out.println("Curve '" + curveName + "' has a 'GLV Type B' endomorphism with these parameters: "); + printGLVTypeBParameters(x9); + } + } + } + + private static void printGLVTypeBParameters(X9ECParameters x9) + { + BigInteger n = x9.getN(); + BigInteger[] v1 = null; + BigInteger[] v2 = null; + + // x^2 + x + 1 = 0 mod n + BigInteger lambda = solveQuadraticEquation(n, ECConstants.ONE, ECConstants.ONE); + + BigInteger[] rt = extEuclidGLV(n, lambda); + v1 = new BigInteger[]{ rt[2], rt[3].negate() }; + v2 = chooseShortest(new BigInteger[]{ rt[0], rt[1].negate() }, new BigInteger[]{ rt[4], rt[5].negate() }); + + /* + * If elements of v2 are not bounded by sqrt(n), then if r1/t1 are relatively prime there + * _may_ yet be a GLV generator, so search for it. See + * "Integer Decomposition for Fast Scalar Multiplication on Elliptic Curves", D. Kim, S. Lim + * (SAC 2002) + */ + if (!isVectorBoundedBySqrt(v2, n) && areRelativelyPrime(v1[0], v1[1])) + { + BigInteger r = v1[0], t = v1[1], s = r.add(t.multiply(lambda)).divide(n); + + BigInteger[] vw = extEuclidBezout(new BigInteger[]{ s.abs(), t.abs() }); + BigInteger v = vw[0], w = vw[1]; + + if (s.signum() < 0) + { + v = v.negate(); + } + if (t.signum() > 0) + { + w = w.negate(); + } + + BigInteger check = s.multiply(v).subtract(t.multiply(w)); + if (!check.equals(ECConstants.ONE)) + { + throw new IllegalStateException(); + } + + BigInteger x = w.multiply(n).subtract(v.multiply(lambda)); + + BigInteger base1 = v.negate(); + BigInteger base2 = x.negate(); + + /* + * We calculate the range(s) conservatively large to avoid messy rounding issues, so + * there may be spurious candidate generators, but we won't miss any. + */ + BigInteger sqrtN = isqrt(n.subtract(ECConstants.ONE)).add(ECConstants.ONE); + + BigInteger[] I1 = calculateRange(base1, sqrtN, t); + BigInteger[] I2 = calculateRange(base2, sqrtN, r); + + BigInteger[] range = intersect(I1, I2); + if (range != null) + { + for (BigInteger alpha = range[0]; alpha.compareTo(range[1]) <= 0; alpha = alpha.add(ECConstants.ONE)) + { + BigInteger[] candidate = new BigInteger[]{ x.add(alpha.multiply(r)), v.add(alpha.multiply(t)) }; + if (isShorter(candidate, v2)) + { + v2 = candidate; + } + } + } + } + + /* + * 'Beta' is a field element of order 3. There are only two such values besides 1; determine which of them + * corresponds to our choice for 'Lambda'. + */ + ECFieldElement beta; + { + ECPoint G = x9.getG().normalize(); + ECPoint mapG = G.multiply(lambda).normalize(); + if (!G.getYCoord().equals(mapG.getYCoord())) + { + throw new IllegalStateException("Derivation of GLV Type B parameters failed unexpectedly"); + } + + BigInteger q = x9.getCurve().getField().getCharacteristic(); + BigInteger e = q.divide(ECConstants.THREE); + + SecureRandom random = new SecureRandom(); + BigInteger b; + do + { + BigInteger r = BigIntegers.createRandomInRange(ECConstants.TWO, q.subtract(ECConstants.TWO), random); + b = r.modPow(e, q); + } + while (b.equals(ECConstants.ONE)); + + beta = x9.getCurve().fromBigInteger(ECConstants.TWO.modPow(e, q)); + + if (!G.getXCoord().multiply(beta).equals(mapG.getXCoord())) + { + beta = beta.square(); + if (!G.getXCoord().multiply(beta).equals(mapG.getXCoord())) + { + throw new IllegalStateException("Derivation of GLV Type B parameters failed unexpectedly"); + } + } + } + + /* + * These parameters are used to avoid division when decomposing the scalar in a GLV point multiplication + */ + BigInteger d = (v1[0].multiply(v2[1])).subtract(v1[1].multiply(v2[0])); + + int bits = n.bitLength() + 2; + BigInteger g1 = roundQuotient(v2[1].shiftLeft(bits), d); + BigInteger g2 = roundQuotient(v1[1].shiftLeft(bits), d).negate(); + + printProperty("Beta", beta.toBigInteger().toString(radix)); + printProperty("Lambda", lambda.toString(radix)); + printProperty("v1", "{ " + v1[0].toString(radix) + ", " + v1[1].toString(radix) + " }"); + printProperty("v2", "{ " + v2[0].toString(radix) + ", " + v2[1].toString(radix) + " }"); + printProperty("(OPT) g1", g1.toString(radix)); + printProperty("(OPT) g2", g2.toString(radix)); + printProperty("(OPT) bits", bits); + } + + private static void printProperty(String name, Object value) + { + StringBuffer sb = new StringBuffer(" "); + sb.append(name); + while (sb.length() < 20) + { + sb.append(' '); + } + sb.append("= "); + sb.append(value.toString()); + System.out.println(sb.toString()); + } + + private static boolean areRelativelyPrime(BigInteger a, BigInteger b) + { + return a.gcd(b).equals(ECConstants.ONE); + } + + private static BigInteger[] calculateRange(BigInteger mid, BigInteger off, BigInteger div) + { + BigInteger i1 = mid.subtract(off).divide(div); + BigInteger i2 = mid.add(off).divide(div); + return order(i1, i2); + } + + private static BigInteger[] extEuclidBezout(BigInteger[] ab) + { + boolean swap = ab[0].compareTo(ab[1]) < 0; + if (swap) + { + swap(ab); + } + + BigInteger r0 = ab[0], r1 = ab[1]; + BigInteger s0 = ECConstants.ONE, s1 = ECConstants.ZERO; + BigInteger t0 = ECConstants.ZERO, t1 = ECConstants.ONE; + + while (r1.compareTo(BigInteger.ONE) > 0) + { + BigInteger[] qr = r0.divideAndRemainder(r1); + BigInteger q = qr[0], r2 = qr[1]; + + BigInteger s2 = s0.subtract(q.multiply(s1)); + BigInteger t2 = t0.subtract(q.multiply(t1)); + + r0 = r1; + r1 = r2; + s0 = s1; + s1 = s2; + t0 = t1; + t1 = t2; + } + + if (r1.signum() <= 0) + { + throw new IllegalStateException(); + } + + BigInteger[] st = new BigInteger[]{ s1, t1 }; + if (swap) + { + swap(st); + } + return st; + } + + private static BigInteger[] extEuclidGLV(BigInteger n, BigInteger lambda) + { + BigInteger r0 = n, r1 = lambda; + // BigInteger s0 = ECConstants.ONE, s1 = ECConstants.ZERO; + BigInteger t0 = ECConstants.ZERO, t1 = ECConstants.ONE; + + for (;;) + { + BigInteger[] qr = r0.divideAndRemainder(r1); + BigInteger q = qr[0], r2 = qr[1]; + + // BigInteger s2 = s0.subtract(q.multiply(s1)); + BigInteger t2 = t0.subtract(q.multiply(t1)); + + if (isLessThanSqrt(r1, n)) + { + return new BigInteger[]{ r0, t0, r1, t1, r2, t2 }; + } + + r0 = r1; + r1 = r2; + // s0 = s1; + // s1 = s2; + t0 = t1; + t1 = t2; + } + } + + private static BigInteger[] chooseShortest(BigInteger[] u, BigInteger[] v) + { + return isShorter(u, v) ? u : v; + } + + private static BigInteger[] intersect(BigInteger[] ab, BigInteger[] cd) + { + BigInteger min = ab[0].max(cd[0]); + BigInteger max = ab[1].min(cd[1]); + if (min.compareTo(max) > 0) + { + return null; + } + return new BigInteger[]{ min, max }; + } + + private static boolean isLessThanSqrt(BigInteger a, BigInteger b) + { + a = a.abs(); + b = b.abs(); + int target = b.bitLength(), maxBits = a.bitLength() * 2, minBits = maxBits - 1; + return minBits <= target && (maxBits < target || a.multiply(a).compareTo(b) < 0); + } + + private static boolean isShorter(BigInteger[] u, BigInteger[] v) + { + BigInteger u1 = u[0].abs(), u2 = u[1].abs(), v1 = v[0].abs(), v2 = v[1].abs(); + + // TODO Check whether "shorter" just means by rectangle norm: + // return u1.max(u2).compareTo(v1.max(v2)) < 0; + + boolean c1 = u1.compareTo(v1) < 0, c2 = u2.compareTo(v2) < 0; + if (c1 == c2) + { + return c1; + } + + BigInteger du = u1.multiply(u1).add(u2.multiply(u2)); + BigInteger dv = v1.multiply(v1).add(v2.multiply(v2)); + + return du.compareTo(dv) < 0; + } + + private static boolean isVectorBoundedBySqrt(BigInteger[] v, BigInteger n) + { + BigInteger max = v[0].abs().max(v[1].abs()); + return isLessThanSqrt(max, n); + } + + private static BigInteger[] order(BigInteger a, BigInteger b) + { + if (a.compareTo(b) <= 0) + { + return new BigInteger[]{ a, b }; + } + return new BigInteger[]{ b, a }; + } + + private static BigInteger roundQuotient(BigInteger x, BigInteger y) + { + boolean negative = (x.signum() != y.signum()); + x = x.abs(); + y = y.abs(); + BigInteger result = x.add(y.shiftRight(1)).divide(y); + return negative ? result.negate() : result; + } + + private static BigInteger solveQuadraticEquation(BigInteger n, BigInteger r, BigInteger s) + { + BigInteger det = r.multiply(r).subtract(s.shiftLeft(2)).mod(n); + + BigInteger root = new ECFieldElement.Fp(n, det).sqrt().toBigInteger(); + if (!root.testBit(0)) + { + root = n.subtract(root); + } + + return root.shiftRight(1); // NOTE: implicit -1 of the low-bit + } + + private static BigInteger isqrt(BigInteger x) + { + BigInteger g0 = x.shiftRight(x.bitLength() / 2); + for (;;) + { + BigInteger g1 = g0.add(x.divide(g0)).shiftRight(1); + if (g1.equals(g0)) + { + return g1; + } + g0 = g1; + } + } + + private static void swap(BigInteger[] ab) + { + BigInteger tmp = ab[0]; + ab[0] = ab[1]; + ab[1] = tmp; + } +} diff --git a/core/src/main/java/org/bouncycastle/util/Arrays.java b/core/src/main/java/org/bouncycastle/util/Arrays.java index 9390fbed..3de0f7a2 100644 --- a/core/src/main/java/org/bouncycastle/util/Arrays.java +++ b/core/src/main/java/org/bouncycastle/util/Arrays.java @@ -323,6 +323,25 @@ public final class Arrays return hc; } + + public static int hashCode(byte[] data, int off, int len) + { + if (data == null) + { + return 0; + } + + int i = len; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= data[off + i]; + } + + return hc; + } public static int hashCode(char[] data) { @@ -374,6 +393,25 @@ public final class Arrays return hc; } + public static int hashCode(int[] data, int off, int len) + { + if (data == null) + { + return 0; + } + + int i = len; + int hc = i + 1; + + while (--i >= 0) + { + hc *= 257; + hc ^= data[off + i]; + } + + return hc; + } + public static int hashCode(short[][][] shorts) { int hc = 0; diff --git a/core/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java b/core/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java index 1ef8f51b..ddcfc34f 100644 --- a/core/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java +++ b/core/src/main/java/org/bouncycastle/util/encoders/Base64Encoder.java @@ -7,20 +7,20 @@ public class Base64Encoder implements Encoder { protected final byte[] encodingTable = - { - (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', - (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', - (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', - (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', - (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', - (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', - (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', - (byte)'v', - (byte)'w', (byte)'x', (byte)'y', (byte)'z', - (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', - (byte)'7', (byte)'8', (byte)'9', - (byte)'+', (byte)'/' - }; + { + (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G', + (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N', + (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', + (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z', + (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g', + (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n', + (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', + (byte)'v', + (byte)'w', (byte)'x', (byte)'y', (byte)'z', + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', + (byte)'7', (byte)'8', (byte)'9', + (byte)'+', (byte)'/' + }; protected byte padding = (byte)'='; diff --git a/core/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java b/core/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java index 3bb594b0..3069c77d 100644 --- a/core/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java +++ b/core/src/main/java/org/bouncycastle/util/encoders/HexEncoder.java @@ -7,11 +7,11 @@ public class HexEncoder implements Encoder { protected final byte[] encodingTable = - { - (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', - (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' - }; - + { + (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', + (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' + }; + /* * set up the decoding table. */ |