|
58 | 58 | import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
|
59 | 59 | import org.bouncycastle.jce.spec.ECNamedCurveSpec;
|
60 | 60 |
|
| 61 | +import org.bouncycastle.math.ec.ECAlgorithms; |
| 62 | +import org.bouncycastle.math.ec.ECCurve; |
61 | 63 | import org.jruby.Ruby;
|
62 | 64 | import org.jruby.RubyArray;
|
| 65 | +import org.jruby.RubyBignum; |
63 | 66 | import org.jruby.RubyBoolean;
|
64 | 67 | import org.jruby.RubyClass;
|
| 68 | +import org.jruby.RubyFixnum; |
65 | 69 | import org.jruby.RubyModule;
|
66 | 70 | import org.jruby.RubyObject;
|
67 | 71 | import org.jruby.RubyString;
|
@@ -931,44 +935,54 @@ private static RaiseException newError(final Ruby runtime, final String message)
|
931 | 935 | return Utils.newError(runtime, Error, message);
|
932 | 936 | }
|
933 | 937 |
|
934 |
| - @JRubyMethod(rest = true, visibility = Visibility.PRIVATE) |
935 |
| - public IRubyObject initialize(final ThreadContext context, final IRubyObject[] args) { |
936 |
| - final Ruby runtime = context.runtime; |
| 938 | + @JRubyMethod(visibility = Visibility.PRIVATE) |
| 939 | + public IRubyObject initialize(final ThreadContext context, final IRubyObject groupOrPoint) { |
| 940 | + getPointAndGroup(context, groupOrPoint); |
937 | 941 |
|
938 |
| - final int argc = Arity.checkArgumentCount(runtime, args, 1, 2); |
939 |
| - final IRubyObject arg = args[0]; |
| 942 | + return this; |
| 943 | + } |
940 | 944 |
|
941 |
| - if ( arg instanceof Point ) { |
942 |
| - this.group = ((Point) arg).group; |
943 |
| - this.point = ((Point) arg).point; |
| 945 | + @JRubyMethod(visibility = Visibility.PRIVATE) |
| 946 | + public IRubyObject initialize(final ThreadContext context, final IRubyObject groupOrPoint, final IRubyObject bn) { |
| 947 | + if (getPointAndGroup(context, groupOrPoint)) { |
944 | 948 | return this;
|
945 | 949 | }
|
946 | 950 |
|
947 |
| - if ( arg instanceof Group ) { |
948 |
| - this.group = (Group) arg; |
| 951 | + final byte[] encoded; |
| 952 | + if (bn instanceof BN) { |
| 953 | + encoded = ((BN) bn).getValue().abs().toByteArray(); |
949 | 954 | } else {
|
950 |
| - throw runtime.newTypeError(arg, _EC(runtime).getClass("Group")); |
| 955 | + encoded = bn.convertToString().getBytes(); |
951 | 956 | }
|
952 |
| - |
953 |
| - if ( argc == 2 ) { // (group, bn) |
954 |
| - final byte[] encoded; |
955 |
| - if (args[1] instanceof BN) { |
956 |
| - encoded = ((BN) args[1]).getValue().abs().toByteArray(); |
957 |
| - } else { |
958 |
| - encoded = args[1].convertToString().getBytes(); |
959 |
| - } |
960 |
| - try { |
961 |
| - this.point = ECPointUtil.decodePoint(group.getCurve(), encoded); |
962 |
| - } |
963 |
| - catch (IllegalArgumentException ex) { |
964 |
| - // MRI: OpenSSL::PKey::EC::Point::Error: invalid encoding |
965 |
| - throw newError(context.runtime, ex.getMessage()); |
966 |
| - } |
| 957 | + try { |
| 958 | + this.point = ECPointUtil.decodePoint(group.getCurve(), encoded); |
| 959 | + } |
| 960 | + catch (IllegalArgumentException ex) { |
| 961 | + // MRI: OpenSSL::PKey::EC::Point::Error: invalid encoding |
| 962 | + throw newError(context.runtime, ex.getMessage()); |
967 | 963 | }
|
968 | 964 |
|
969 | 965 | return this;
|
970 | 966 | }
|
971 | 967 |
|
| 968 | + private boolean getPointAndGroup(ThreadContext context, IRubyObject groupOrPoint) { |
| 969 | + final Ruby runtime = context.runtime; |
| 970 | + |
| 971 | + if ( groupOrPoint instanceof Point) { |
| 972 | + this.group = ((Point) groupOrPoint).group; |
| 973 | + this.point = ((Point) groupOrPoint).point; |
| 974 | + return true; |
| 975 | + } |
| 976 | + |
| 977 | + if ( groupOrPoint instanceof Group) { |
| 978 | + this.group = (Group) groupOrPoint; |
| 979 | + this.point = this.group.getParamSpec().getGenerator(); |
| 980 | + } else { |
| 981 | + throw runtime.newTypeError(groupOrPoint, _EC(runtime).getClass("Group")); |
| 982 | + } |
| 983 | + return false; |
| 984 | + } |
| 985 | + |
972 | 986 | @Override
|
973 | 987 | @JRubyMethod(name = { "==", "eql?" })
|
974 | 988 | public IRubyObject op_equal(final ThreadContext context, final IRubyObject obj) {
|
@@ -1059,6 +1073,121 @@ public IRubyObject inspect() {
|
1059 | 1073 | return ObjectSupport.inspect(this, (List) Collections.singletonList(entry));
|
1060 | 1074 | }
|
1061 | 1075 |
|
| 1076 | + @JRubyMethod(name = "add") |
| 1077 | + public IRubyObject add(final ThreadContext context, final IRubyObject other) { |
| 1078 | + Ruby runtime = context.runtime; |
| 1079 | + |
| 1080 | + org.bouncycastle.math.ec.ECPoint pointSelf, pointOther, pointResult; |
| 1081 | + |
| 1082 | + Group groupV = this.group; |
| 1083 | + Point result; |
| 1084 | + |
| 1085 | + ECCurve selfCurve = EC5Util.convertCurve(groupV.getCurve()); |
| 1086 | + pointSelf = EC5Util.convertPoint(selfCurve, asECPoint()); |
| 1087 | + |
| 1088 | + Point otherPoint = (Point) other; |
| 1089 | + ECCurve otherCurve = EC5Util.convertCurve(otherPoint.group.getCurve()); |
| 1090 | + pointOther = EC5Util.convertPoint(otherCurve, otherPoint.asECPoint()); |
| 1091 | + |
| 1092 | + pointResult = pointSelf.add(pointOther); |
| 1093 | + if (pointResult == null) { |
| 1094 | + newECError(runtime, "EC_POINT_add"); |
| 1095 | + } |
| 1096 | + |
| 1097 | + result = new Point(runtime, EC5Util.convertPoint(pointResult), group); |
| 1098 | + |
| 1099 | + return result; |
| 1100 | + } |
| 1101 | + |
| 1102 | + @JRubyMethod(name = "mul") |
| 1103 | + public IRubyObject mul(final ThreadContext context, final IRubyObject bn1) { |
| 1104 | + Ruby runtime = context.runtime; |
| 1105 | + |
| 1106 | + if (bn1 instanceof RubyArray) { |
| 1107 | + throw runtime.newNotImplementedError("calling #mul with arrays is not supported by this OpenSSL version"); |
| 1108 | + } |
| 1109 | + |
| 1110 | + org.bouncycastle.math.ec.ECPoint pointSelf; |
| 1111 | + |
| 1112 | + Group groupV = this.group; |
| 1113 | + |
| 1114 | + ECCurve selfCurve = EC5Util.convertCurve(groupV.getCurve()); |
| 1115 | + pointSelf = EC5Util.convertPoint(selfCurve, asECPoint()); |
| 1116 | + |
| 1117 | + BigInteger bn = getBigInteger(context, bn1); |
| 1118 | + |
| 1119 | + org.bouncycastle.math.ec.ECPoint mulPoint = ECAlgorithms.referenceMultiply(pointSelf, bn); |
| 1120 | + if (mulPoint == null) { |
| 1121 | + throw newECError(runtime, "bad multiply result"); |
| 1122 | + } |
| 1123 | + |
| 1124 | + return new Point(runtime, EC5Util.convertPoint(mulPoint), groupV); |
| 1125 | + } |
| 1126 | + |
| 1127 | + @JRubyMethod(name = "mul") |
| 1128 | + public IRubyObject mul(final ThreadContext context, final IRubyObject bn1, final IRubyObject bn2) { |
| 1129 | + Ruby runtime = context.runtime; |
| 1130 | + |
| 1131 | + if (bn1 instanceof RubyArray) { |
| 1132 | + throw runtime.newNotImplementedError("calling #mul with arrays is not supported by this OpenSSL version"); |
| 1133 | + } |
| 1134 | + |
| 1135 | + org.bouncycastle.math.ec.ECPoint pointSelf, pointResult; |
| 1136 | + |
| 1137 | + Group groupV = this.group; |
| 1138 | + |
| 1139 | + ECCurve selfCurve = EC5Util.convertCurve(groupV.getCurve()); |
| 1140 | + pointSelf = EC5Util.convertPoint(selfCurve, asECPoint()); |
| 1141 | + |
| 1142 | + ECCurve resultCurve = EC5Util.convertCurve(groupV.getCurve()); |
| 1143 | + pointResult = EC5Util.convertPoint(resultCurve, ((Point) groupV.generator(context)).asECPoint()); |
| 1144 | + |
| 1145 | + BigInteger bn = getBigInteger(context, bn1); |
| 1146 | + BigInteger bn_g = getBigInteger(context, bn2); |
| 1147 | + |
| 1148 | + org.bouncycastle.math.ec.ECPoint mulPoint = ECAlgorithms.sumOfTwoMultiplies(pointResult, bn_g, pointSelf, bn); |
| 1149 | + |
| 1150 | + if (mulPoint == null) { |
| 1151 | + throw newECError(runtime, "bad multiply result"); |
| 1152 | + } |
| 1153 | + |
| 1154 | + return new Point(runtime, EC5Util.convertPoint(mulPoint), groupV); |
| 1155 | + } |
| 1156 | + |
| 1157 | + @JRubyMethod(name = "mul") |
| 1158 | + public IRubyObject mul(final ThreadContext context, final IRubyObject bns, final IRubyObject points, final IRubyObject bn2) { |
| 1159 | + throw context.runtime.newNotImplementedError("calling #mul with arrays is not supported by this OpenSSL version"); |
| 1160 | + } |
| 1161 | + |
| 1162 | + @Deprecated |
| 1163 | + public IRubyObject initialize(final ThreadContext context, final IRubyObject[] args) { |
| 1164 | + final int argc = Arity.checkArgumentCount(context.runtime, args, 1, 2); |
| 1165 | + |
| 1166 | + switch (argc) { |
| 1167 | + case 1: |
| 1168 | + return initialize(context, args[0]); |
| 1169 | + case 2: |
| 1170 | + return initialize(context, args[0], args[1]); |
| 1171 | + default: |
| 1172 | + throw context.runtime.newArgumentError(args.length, 1); |
| 1173 | + } |
| 1174 | + } |
| 1175 | + |
| 1176 | + } |
| 1177 | + |
| 1178 | + private static BigInteger getBigInteger(ThreadContext context, IRubyObject arg1) { |
| 1179 | + BigInteger bn; |
| 1180 | + if (arg1 instanceof RubyFixnum) { |
| 1181 | + bn = BigInteger.valueOf(arg1.convertToInteger().getLongValue()); |
| 1182 | + } else if (arg1 instanceof RubyBignum) { |
| 1183 | + bn = ((RubyBignum) arg1).getValue(); |
| 1184 | + } else if (arg1 instanceof BN) { |
| 1185 | + bn = ((BN) arg1).getValue(); |
| 1186 | + } else { |
| 1187 | + Ruby runtime = context.runtime; |
| 1188 | + throw runtime.newTypeError(arg1, runtime.getInteger()); |
| 1189 | + } |
| 1190 | + return bn; |
1062 | 1191 | }
|
1063 | 1192 |
|
1064 | 1193 | static byte[] encode(final ECPublicKey pubKey) {
|
|
0 commit comments