blob: 7d55769f83e4fc3fbbb8912a0c15c2eb3a479e73 [file] [log] [blame]
// See file LICENSE for more information.
library api.ecc;
import 'dart:typed_data';
import 'package:pointycastle/api.dart';
import 'package:pointycastle/src/registry/registry.dart';
export 'ecdh.dart';
/// Standard ECC curve description
abstract class ECDomainParameters {
/// Get this domain's standard name.
String get domainName;
ECCurve get curve;
List<int>? get seed;
ECPoint get G;
BigInt get n;
/// Create a curve description from its standard name
factory ECDomainParameters(String domainName) =>
registry.create<ECDomainParameters>(domainName);
}
/// Type for coordinates of an [ECPoint]
abstract class ECFieldElement {
BigInt? toBigInteger();
String get fieldName;
int get fieldSize;
int get byteLength;
ECFieldElement operator +(ECFieldElement b);
ECFieldElement operator -(ECFieldElement b);
ECFieldElement operator *(ECFieldElement b);
ECFieldElement operator /(ECFieldElement b);
ECFieldElement operator -();
ECFieldElement invert();
ECFieldElement square();
ECFieldElement? sqrt();
}
/// An elliptic curve point
abstract class ECPoint {
ECCurve get curve;
ECFieldElement? get x;
ECFieldElement? get y;
bool get isCompressed;
bool get isInfinity;
@override
bool operator ==(other);
Uint8List getEncoded([bool compressed = true]);
ECPoint? operator +(ECPoint? b);
ECPoint? operator -(ECPoint b);
ECPoint operator -();
ECPoint? twice();
/// Multiply this point by the given number [k].
ECPoint? operator *(BigInt? k);
@override
int get hashCode => super.hashCode;
}
/// An elliptic curve
abstract class ECCurve {
ECFieldElement? get a;
ECFieldElement? get b;
int get fieldSize;
ECPoint? get infinity;
/// Create an [ECFieldElement] on this curve from its big integer value.
ECFieldElement fromBigInteger(BigInt x);
/// Create an [ECPoint] on its curve from its coordinates
ECPoint createPoint(BigInt x, BigInt y, [bool withCompression = false]);
ECPoint 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 Fp (X9.62 s 4.2.1 pg 17).
ECPoint? decodePoint(List<int> encoded);
}
/// Base class for asymmetric keys in ECC
abstract class ECAsymmetricKey implements AsymmetricKey {
/// The domain parameters of this key
final ECDomainParameters? parameters;
/// Create an asymmetric key for the given domain parameters
ECAsymmetricKey(this.parameters);
}
/// Private keys in ECC
class ECPrivateKey extends ECAsymmetricKey implements PrivateKey {
/// ECC's d private parameter
final BigInt? d;
/// Create an ECC private key for the given d and domain parameters.
ECPrivateKey(this.d, ECDomainParameters? parameters) : super(parameters);
@override
bool operator ==(other) {
if (other is! ECPrivateKey) return false;
return (other.parameters == parameters) && (other.d == d);
}
@override
int get hashCode {
return parameters.hashCode + d.hashCode;
}
}
/// Public keys in ECC
class ECPublicKey extends ECAsymmetricKey implements PublicKey {
/// ECC's Q public parameter
final ECPoint? Q;
/// Create an ECC public key for the given Q and domain parameters.
ECPublicKey(this.Q, ECDomainParameters? parameters) : super(parameters);
@override
bool operator ==(other) {
if (other is! ECPublicKey) return false;
return (other.parameters == parameters) && (other.Q == Q);
}
@override
int get hashCode {
return parameters.hashCode + Q.hashCode;
}
}
/// A [Signature] created with ECC.
class ECSignature implements Signature {
final BigInt r;
final BigInt s;
ECSignature(this.r, this.s);
/// Returns true if s is in lower-s form, false otherwise.
bool isNormalized(ECDomainParameters curveParams) {
return !(s.compareTo(curveParams.n >> 1) > 0);
}
///
/// 'normalize' this signature by converting its s to lower-s form if necessary
/// This is required to validate this signature with some libraries such as libsecp256k1
/// which enforce lower-s form for all signatures to combat ecdsa signature malleability
///
/// Returns this if the signature was already normalized, or a copy if it is changed.
///
ECSignature normalize(ECDomainParameters curveParams) {
if (isNormalized(curveParams)) {
return this;
}
return ECSignature(r, curveParams.n - s);
}
@override
String toString() => '(${r.toString()},${s.toString()})';
@override
bool operator ==(other) {
if (other is! ECSignature) return false;
return (other.r == r) && (other.s == s);
}
@override
int get hashCode {
return r.hashCode + s.hashCode;
}
}
/// A pair of [ECPoint]s.
class ECPair {
final ECPoint x;
final ECPoint y;
const ECPair(this.x, this.y);
@override
bool operator ==(other) {
if (other is! ECPair) return false;
return (other.x == x) && (other.y == y);
}
@override
int get hashCode => x.hashCode + y.hashCode * 37;
}
/// The encryptor using Elliptic Curve
abstract class ECEncryptor {
ECPair encrypt(ECPoint point);
/// Initialize the encryptor.
void init(CipherParameters params);
}
/// The decryptor using Elliptic Curve
abstract class ECDecryptor {
ECPoint decrypt(ECPair pair);
/// Initialize the decryptor.
void init(CipherParameters params);
}
abstract class ECDHAgreement {
/// initialise the agreement engine.
void init(ECPrivateKey param);
/// return the field size for the agreement algorithm in bytes.
int getFieldSize();
/// given a public key from a given party calculate the next
/// message in the agreement sequence.
BigInt calculateAgreement(ECPublicKey pubKey);
}