| // See file LICENSE for more information. |
| |
| library impl.ecc.ecc_base; |
| //TODO I think this stuff might be moved to src/impl |
| |
| import 'dart:typed_data'; |
| |
| import 'package:pointycastle/ecc/api.dart'; |
| import 'package:pointycastle/src/utils.dart' as utils; |
| |
| /// Implementation of [ECDomainParameters] |
| class ECDomainParametersImpl implements ECDomainParameters { |
| @override |
| final String domainName; |
| @override |
| final ECCurve curve; |
| @override |
| final List<int>? seed; |
| @override |
| final ECPoint G; |
| @override |
| final BigInt n; |
| BigInt? _h; |
| |
| ECDomainParametersImpl(this.domainName, this.curve, this.G, this.n, |
| [this._h, this.seed]) { |
| _h ??= BigInt.one; |
| } |
| |
| BigInt? get h => _h; |
| } |
| |
| /// Base implementation for [ECFieldElement] |
| abstract class ECFieldElementBase implements ECFieldElement { |
| @override |
| BigInt? toBigInteger(); |
| |
| @override |
| String get fieldName; |
| |
| @override |
| int get fieldSize; |
| |
| @override |
| int get byteLength => (fieldSize + 7) ~/ 8; |
| |
| @override |
| ECFieldElementBase operator +(covariant ECFieldElementBase b); |
| |
| @override |
| ECFieldElementBase operator -(covariant ECFieldElementBase b); |
| |
| @override |
| ECFieldElementBase operator *(covariant ECFieldElementBase b); |
| |
| @override |
| ECFieldElementBase operator /(covariant ECFieldElementBase b); |
| |
| @override |
| ECFieldElementBase operator -(); |
| |
| @override |
| ECFieldElementBase invert(); |
| |
| @override |
| ECFieldElementBase square(); |
| |
| @override |
| ECFieldElementBase? sqrt(); |
| |
| @override |
| String toString() => toBigInteger().toString(); |
| } |
| |
| /// Base implementation for [ECPoint] |
| abstract class ECPointBase implements ECPoint { |
| @override |
| final ECCurveBase curve; |
| @override |
| final ECFieldElementBase? x; |
| @override |
| final ECFieldElementBase? y; |
| @override |
| final bool isCompressed; |
| final ECMultiplier _multiplier; |
| |
| PreCompInfo? _preCompInfo; |
| |
| ECPointBase(this.curve, this.x, this.y, this.isCompressed, |
| [this._multiplier = _fpNafMultiplier]); |
| |
| @override |
| bool get isInfinity => x == null && y == null; |
| |
| set preCompInfo(PreCompInfo preCompInfo) { |
| _preCompInfo = preCompInfo; |
| } |
| |
| @override |
| bool operator ==(Object other) { |
| if (other is ECPointBase) { |
| if (isInfinity) { |
| return other.isInfinity; |
| } |
| return x == other.x && y == other.y; |
| } |
| return false; |
| } |
| |
| @override |
| String toString() => '($x,$y)'; |
| |
| @override |
| int get hashCode { |
| if (isInfinity) { |
| return 0; |
| } |
| return x.hashCode ^ y.hashCode; |
| } |
| |
| @override |
| Uint8List getEncoded([bool compressed = true]); |
| |
| @override |
| ECPointBase? operator +(covariant ECPointBase? b); |
| |
| @override |
| ECPointBase? operator -(covariant ECPointBase b); |
| |
| @override |
| ECPointBase operator -(); |
| |
| @override |
| ECPointBase? twice(); |
| |
| /// Multiplies this <code>ECPoint</code> by the given number. |
| /// @param k The multiplicator. |
| /// @return <code>k * this</code>. |
| @override |
| ECPointBase? operator *(BigInt? k) { |
| if (k!.sign < 0) { |
| throw ArgumentError('The multiplicator cannot be negative'); |
| } |
| |
| if (isInfinity) { |
| return this; |
| } |
| |
| if (k.sign == 0) { |
| return curve.infinity; |
| } |
| |
| return _multiplier(this, k, _preCompInfo); |
| } |
| } |
| |
| /// Base implementation for [ECCurve] |
| abstract class ECCurveBase implements ECCurve { |
| ECFieldElementBase? _a; |
| ECFieldElementBase? _b; |
| |
| ECCurveBase(BigInt? a, BigInt? b) { |
| _a = fromBigInteger(a); |
| _b = fromBigInteger(b); |
| } |
| |
| @override |
| ECFieldElementBase? get a => _a; |
| |
| @override |
| ECFieldElementBase? get b => _b; |
| |
| @override |
| int get fieldSize; |
| |
| @override |
| ECPointBase? get infinity; |
| |
| @override |
| ECFieldElementBase fromBigInteger(BigInt? x); |
| |
| @override |
| ECPointBase createPoint(BigInt x, BigInt y, [bool withCompression = false]); |
| |
| @override |
| ECPointBase decompressPoint(int yTilde, BigInt x1); |
| |
| /// Decode a point on this curve from its ASN.1 encoding. The different |
| /// encodings are taken account of, including point compression for |
| /// <code>F<sub>p</sub></code> (X9.62 s 4.2.1 pg 17). |
| /// @return The decoded point. |
| @override |
| ECPointBase? decodePoint(List<int> encoded) { |
| ECPointBase? p; |
| var expectedLength = (fieldSize + 7) ~/ 8; |
| |
| switch (encoded[0]) { |
| case 0x00: // infinity |
| if (encoded.length != 1) { |
| throw ArgumentError('Incorrect length for infinity encoding'); |
| } |
| |
| p = infinity; |
| break; |
| |
| case 0x02: // compressed |
| case 0x03: // compressed |
| if (encoded.length != (expectedLength + 1)) { |
| throw ArgumentError('Incorrect length for compressed encoding'); |
| } |
| |
| var yTilde = encoded[0] & 1; |
| var x1 = _fromArray(encoded, 1, expectedLength); |
| |
| p = decompressPoint(yTilde, x1); |
| break; |
| |
| case 0x04: // uncompressed |
| case 0x06: // hybrid |
| case 0x07: // hybrid |
| if (encoded.length != (2 * expectedLength + 1)) { |
| throw ArgumentError( |
| 'Incorrect length for uncompressed/hybrid encoding'); |
| } |
| |
| var x1 = _fromArray(encoded, 1, expectedLength); |
| var y1 = _fromArray(encoded, 1 + expectedLength, expectedLength); |
| |
| p = createPoint(x1, y1, false); |
| break; |
| |
| default: |
| throw ArgumentError( |
| 'Invalid point encoding 0x${encoded[0].toRadixString(16)}'); |
| } |
| |
| return p; |
| } |
| |
| BigInt _fromArray(List<int> buf, int off, int length) { |
| return utils.decodeBigIntWithSign(1, buf.sublist(off, off + length)); |
| } |
| } |
| |
| /// Interface for classes storing precomputation data for multiplication algorithms. |
| abstract class PreCompInfo {} |
| |
| /// Interface for functions encapsulating a point multiplication algorithm for [ECPointBase]. Multiplies [p] by [k], i.e. [p] is |
| /// added [k] times to itself. |
| typedef ECMultiplier = ECPointBase? Function( |
| ECPointBase p, BigInt? k, PreCompInfo? preCompInfo); |
| |
| bool _testBit(BigInt i, int n) { |
| return i & (BigInt.one << n) != BigInt.zero; |
| } |
| |
| /// Function implementing the NAF (Non-Adjacent Form) multiplication algorithm. |
| ECPointBase? _fpNafMultiplier( |
| ECPointBase p, BigInt? k, PreCompInfo? preCompInfo) { |
| // TODO Probably should try to add this |
| // BigInt e = k.mod(n); // n == order of p |
| var e = k; |
| var h = e! * BigInt.from(3); |
| |
| var neg = -p; |
| ECPointBase? R = p; |
| |
| for (var i = h.bitLength - 2; i > 0; --i) { |
| R = R!.twice(); |
| |
| var hBit = _testBit(h, i); |
| var eBit = _testBit(e, i); |
| |
| if (hBit != eBit) { |
| R = R! + (hBit ? p : neg); |
| } |
| } |
| |
| return R; |
| } |