// See file LICENSE for more information. library impl.asymmetric.ecc.elgamal; import 'package:pointycastle/export.dart'; import 'package:pointycastle/src/platform_check/platform_check.dart'; BigInt _generateK(BigInt n, SecureRandom random) { var nBitLength = n.bitLength; BigInt k; do { k = random.nextBigInteger(nBitLength); } while ((k == BigInt.zero) || (k.compareTo(n) >= 0)); return k; } SecureRandom _newSecureRandom() => FortunaRandom() ..seed(KeyParameter(Platform.instance.platformEntropySource().getBytes(32))); /// The basic ElGamal encryptor using Elliptic Curve class ECElGamalEncryptor implements ECEncryptor { ECPublicKey? _key; late SecureRandom _random; /// Process a single EC [point] using the basic ElGamal algorithm. @override ECPair encrypt(ECPoint point) { if (_key == null) { throw StateError('ECElGamalEncryptor is not initialised'); } var key = _key!; var ec = key.parameters!; var k = _generateK(ec.n, _random); return ECPair( (ec.G * k)!, ((key.Q! * k)! + point)!, ); } @override void init(CipherParameters params) { AsymmetricKeyParameter akparams; if (params is ParametersWithRandom) { akparams = params.parameters as AsymmetricKeyParameter; _random = params.random; } else { akparams = params as AsymmetricKeyParameter; _random = _newSecureRandom(); } var k = akparams.key as ECAsymmetricKey; if (k is! ECPublicKey) { throw ArgumentError('ECPublicKey is required for encryption.'); } _key = k; } } /// The basic ElGamal decryptor using Elliptic Curve class ECElGamalDecryptor implements ECDecryptor { ECPrivateKey? _key; /// Decrypt an EC [pair] producing the original [ECPoint]. @override ECPoint decrypt(ECPair pair) { if (_key == null) { throw StateError('ECElGamalEncryptor is not initialised'); } return (pair.y - (pair.x * _key!.d)!)!; } @override void init(CipherParameters params) { var akparams = params as AsymmetricKeyParameter; var k = akparams.key as ECAsymmetricKey; if (k is! ECPrivateKey) { throw ArgumentError('ECPrivateKey is required for decryption.'); } _key = k; } }