// This file has been migrated. library impl.digest.cshake; import 'dart:typed_data'; import 'package:pointycastle/api.dart'; import 'package:pointycastle/digests/shake.dart'; import 'package:pointycastle/digests/xof_utils.dart'; import 'package:pointycastle/src/registry/registry.dart'; import 'package:pointycastle/src/utils.dart'; /// /// implementation of SHAKE based on following KeccakNISTInterface.c from http://keccak.noekeon.org/ /// /// Following the naming conventions used in the C source code to enable easy review of the implementation. /// class CSHAKEDigest extends SHAKEDigest implements Xof { static final RegExp _cshakeREGEX = RegExp(r'^CSHAKE-([0-9]+)$'); /// Intended for internal use. static final FactoryConfig factoryConfig = DynamicFactoryConfig( Digest, _cshakeREGEX, (_, final Match match) => () { var bitLength = int.parse(match.group(1)!); return CSHAKEDigest(bitLength); }); Uint8List? _diff; final _padding = Uint8List(100); CSHAKEDigest([int bitLength = 256, Uint8List? N, Uint8List? S]) { switch (bitLength) { case 128: case 256: init(bitLength); if ((N == null || N.isEmpty) && (S == null || S.isEmpty)) { _diff = null; } else { _diff = concatUint8List([ XofUtils.leftEncode(rate ~/ 8), _encodeString(N), _encodeString(S) ]); _diffPadAndAbsorb(); } break; default: throw StateError( 'invalid bitLength ($bitLength) for CSHAKE must only be 128 or 256'); } } @override String get algorithmName => 'CSHAKE-$fixedOutputLength'; @override int doOutput(Uint8List out, int outOff, int outLen) { if (_diff != null) { if (!squeezing) { absorbBits(0x00, 2); } squeeze(out, outOff, outLen * 8); return outLen; } else { return super.doOutput(out, outOff, outLen); } } @override void update(Uint8List inp, int inpOff, int len) { absorbRange(inp, inpOff, len); } @override void reset() { super.reset(); if (_diff != null) { _diffPadAndAbsorb(); } } // bytepad in SP 800-185 void _diffPadAndAbsorb() { var blockSize = rate ~/ 8; absorbRange(_diff!, 0, _diff!.length); var delta = _diff!.length % blockSize; // only add padding if needed if (delta != 0) { var required = blockSize - delta; while (required > _padding.length) { absorbRange(_padding, 0, _padding.length); required -= _padding.length; } absorbRange(_padding, 0, required); } } Uint8List _encodeString(Uint8List? str) { if (str == null || str.isEmpty) { return XofUtils.leftEncode(0); } return concatUint8List([XofUtils.leftEncode(str.length * 8), str]); } }