Skip to content

Commit

Permalink
API breaks changes due to complete refactoring ByteList class
Browse files Browse the repository at this point in the history
  • Loading branch information
ilap committed Jul 13, 2022
1 parent eda0f0c commit 2b11d35
Show file tree
Hide file tree
Showing 24 changed files with 164 additions and 119 deletions.
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## v0.5.0
API Break changes see details below:
- Renamed HexCoder to Base16Encoder to align with Base32, Bech32 implementations
- Rename Bech32Coder to Bech32Encoder for similar reasons above.
- Added decodeNoHrpCheck static fucntion to Bech32Encoder for being able to decode and alreay encoded bech32 string.
- Made internal Bech32 classes private.
- Removed unnecessary fromList constructors, as ByteList based default constructors require Iterable
- Added
- ByteList.withConstraint: Create a ByteList wit min, max length set to constraint specified
- ByteList.decodeWithConstraint: Same as above but from (base16, bech32 etc) encoded strings.
- ByteList.withConstraintRange: Create a ByteList within the min, max length range i.e.,
the created ByteList mist be in the range.
- ByteList.decodeWithConstraintRange: Same as above but from (base16, bech32 etc) encoded strings.
- Refactored the code based on these above changes.
## v0.4.2
Added bytes length for decoding ByteList

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Thes library has the aim of
1. Add the following into the `pubspec.yaml` of your dart package:
``` yaml
dependencies:
pinenacl: ^0.4.1
pinenacl: ^0.5.0
```
2. You can install now from the command line with pub:
Expand Down
2 changes: 1 addition & 1 deletion example/hashing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:pinenacl/src/digests/digests.dart';
import 'package:pinenacl/tweetnacl.dart';

void main() {
const hex = HexCoder.instance;
const hex = Base16Encoder.instance;

print('\n### Hashing - Blake2b Example ###\n');

Expand Down
2 changes: 1 addition & 1 deletion example/signature.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:pinenacl/ed25519.dart';

void main() {
const hex = HexCoder.instance;
const hex = Base16Encoder.instance;
print('\n### Digital Signatures - Signing Example ###\n');

/// Signer’s perspective (SigningKey)
Expand Down
93 changes: 68 additions & 25 deletions lib/api/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,76 @@
part of pinenacl.api;

abstract class AsymmetricKey extends ByteList with Encodable {
AsymmetricKey(Uint8List data, [int? keyLength]) : super(data, keyLength);
AsymmetricKey.fromList(Uint8List data) : super.fromList(data);
AsymmetricKey(Uint8List bytes, {required int keyLength})
: super.withConstraint(bytes, constraintLength: keyLength);
AsymmetricPublicKey get publicKey;
}

abstract class AsymmetricPublicKey extends AsymmetricKey {
AsymmetricPublicKey(Uint8List data, [int? bytesLength])
: super(data, bytesLength);
AsymmetricPublicKey.fromList(Uint8List data) : super.fromList(data);
AsymmetricPublicKey(Uint8List bytes, {required int keyLength})
: super(bytes, keyLength: keyLength);
}

abstract class AsymmetricPrivateKey extends AsymmetricKey {
AsymmetricPrivateKey(Uint8List data, [int? keyLength])
: super(data, keyLength);
AsymmetricPrivateKey(Uint8List bytes, {required int keyLength})
: super(bytes, keyLength: keyLength);
}

///
/// `ByteList` is the base of the PineNaCl cryptographic library,
/// which is based on the unmodifiable Uin8List class
/// The bytelist can be created either from
/// - hex string (with or without '0x' prefix) or
/// - List of int's
///
/// ByteList can have a `min` and `max` length specified.
/// - `minLength` means the length of the constructable ByteList must be equal
/// of bigger.
/// - `maxLength` means the ByteList length must be less (till `minLength`) or
/// equal.
///
/// Theses two options can be used for creating a class with fixed-length ByteList or
/// a class which has some constraints e.g., a class that can only create a ByteList
/// that is longer or equal than 16 and shorter or equal than 32.
///
class ByteList with ListMixin<int>, Encodable {
ByteList(Iterable<int> bytes, [int? bytesLength])
: _u8l = _constructList(
bytes, bytesLength ?? bytes.length, bytesLength ?? bytes.length);

ByteList.fromList(Uint8List list,
[int minLength = _minLength, int maxLength = _maxLength])
: _u8l = _constructList(list, minLength, maxLength);

ByteList.decode(String data, {Encoder defaultDecoder = decoder, int? bytesLength})
: this(defaultDecoder.decode(data), bytesLength);
/// It creates an data's length ByteList
ByteList(Iterable<int> data)
: _u8l = _constructList(data, data.length, data.length);

/// It creates a ByteList and checks wheter the data's length is equal with
/// the specified constraint (min and max length equal).
ByteList.withConstraint(Iterable<int> data, {required int constraintLength})
: _u8l = _constructList(data, constraintLength, constraintLength);

/// It creates a ByteList and checks wheter the data's length is equal with
/// the specified constraints (allowed range i.e., min and max length)
///
/// e.g. data.length >= min and data.length <= max.
ByteList.withConstraintRange(Iterable<int> data,
{int min = _minLength, int max = _maxLength})
: _u8l = _constructList(data, min, max);

/// Decoding encoded String to a ByteList. There is no size constraints for the
/// decoded bytes.
/// TODO: create unit tests for decoding constructors.
ByteList.decode(String encodedString, {Encoder coder = decoder})
: this(coder.decode(encodedString));

/// Decoding encoded string to a ByteList with the expected length of the
/// encoded bytes.
ByteList.decodeWithConstraint(String encodedString,
{Encoder coder = decoder, required int constraintLength})
: this.withConstraint(coder.decode(encodedString),
constraintLength: constraintLength);

/// Decoding encoded string to a ByteList with the expected min and max lengths of the
/// encoded bytes.
ByteList.decodeWithConstraintRange(String encodedString,
{Encoder coder = decoder, int min = _minLength, int max = _maxLength})
: this.withConstraintRange(coder.decode(encodedString),
min: min, max: max);

static const _minLength = 0;

Expand All @@ -41,16 +82,16 @@ class ByteList with ListMixin<int>, Encodable {
final Uint8List _u8l;

static Uint8List _constructList(
Iterable<int> list, int minLength, int maxLength) {
if (list.length < minLength || list.length > maxLength) {
Iterable<int> data, int minLength, int maxLength) {
if (data.length < minLength || data.length > maxLength) {
throw Exception(
'The list length (${list.length}) is invalid (min: $minLength, max: $maxLength)');
'The list length (${data.length}) is invalid (min: $minLength, max: $maxLength)');
}
return UnmodifiableUint8ListView(Uint8List.fromList(list.toList()));
return UnmodifiableUint8ListView(Uint8List.fromList(data.toList()));
}

// Default encoder/decoder is the HexCoder()
static const decoder = HexCoder.instance;
static const decoder = Base16Encoder.instance;

@override
Encoder get encoder => decoder;
Expand Down Expand Up @@ -88,14 +129,16 @@ class ByteList with ListMixin<int>, Encodable {
@override
ByteList sublist(int start, [int? end]) {
final sublist = _u8l.sublist(start, end ?? _u8l.length);
return ByteList(sublist, sublist.length);
return ByteList.withConstraint(sublist, constraintLength: sublist.length);
}
}

mixin Suffix on ByteList {
int get prefixLength;
ByteList get prefix => ByteList(take(prefixLength), prefixLength);
ByteList get suffix => ByteList(skip(prefixLength), length - prefixLength);
ByteList get prefix => ByteList.withConstraint(take(prefixLength),
constraintLength: prefixLength);
ByteList get suffix => ByteList.withConstraint(skip(prefixLength),
constraintLength: length - prefixLength);
}

extension ByteListExtension on ByteList {
Expand Down
17 changes: 9 additions & 8 deletions lib/api/authenticated_encryption.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ typedef Crypting = Uint8List Function(
Uint8List out, Uint8List text, int textLen, Uint8List nonce, Uint8List k);

abstract class BoxBase extends ByteList {
BoxBase.fromList(Uint8List list) : super.fromList(list);
BoxBase.fromList(Uint8List list) : super(list);

late Crypting doEncrypt;
late Crypting doDecrypt;
Expand Down Expand Up @@ -46,10 +46,11 @@ abstract class BoxBase extends ByteList {

class EncryptedMessage extends ByteList with Suffix {
EncryptedMessage({required Uint8List nonce, required Uint8List cipherText})
: super.fromList((nonce + cipherText).toUint8List(), nonceLength,
nonce.length + cipherText.length);
: super.withConstraintRange((nonce + cipherText).toUint8List(),
min: nonceLength, max: nonce.length + cipherText.length);

EncryptedMessage.fromList(Uint8List list) : super.fromList(list, nonceLength);
EncryptedMessage.fromList(Uint8List bytes)
: super.withConstraintRange(bytes, min: nonceLength);

static const nonceLength = 24;

Expand All @@ -61,12 +62,12 @@ class EncryptedMessage extends ByteList with Suffix {
}

class PublicKey extends AsymmetricPublicKey {
PublicKey(Uint8List bytes) : super(bytes, keyLength);
PublicKey(Uint8List bytes) : super(bytes, keyLength: keyLength);

PublicKey.decode(String keyString, [Encoder coder = decoder])
: this(coder.decode(keyString));

static const decoder = Bech32Coder(hrp: 'x25519_pk');
static const decoder = Bech32Encoder(hrp: 'x25519_pk');

@override
PublicKey get publicKey => this;
Expand All @@ -84,7 +85,7 @@ class PublicKey extends AsymmetricPublicKey {
/// ECDH
///
class PrivateKey extends AsymmetricPrivateKey {
PrivateKey(Uint8List secret) : super(secret, keyLength);
PrivateKey(Uint8List secret) : super(secret, keyLength: keyLength);

PrivateKey.fromSeed(Uint8List seed) : this(_seedToHash(seed));

Expand All @@ -93,7 +94,7 @@ class PrivateKey extends AsymmetricPrivateKey {
PrivateKey.decode(String keyString, [Encoder coder = decoder])
: this(coder.decode(keyString));

static const decoder = Bech32Coder(hrp: 'x25519_sk');
static const decoder = Bech32Encoder(hrp: 'x25519_sk');
static const seedSize = TweetNaCl.seedSize;
static const keyLength = TweetNaCl.secretKeyLength;

Expand Down
2 changes: 2 additions & 0 deletions lib/api/encoding.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
part of pinenacl.api;

/// The Encoder interface for classes that are capable for encoding data,
/// therefore they need decoding function too.
abstract class Encoder {
String encode(ByteList data);
Uint8List decode(String data);
Expand Down
2 changes: 1 addition & 1 deletion lib/encoding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ import 'package:pinenacl/api.dart';

part 'src/encoding/base32_encoder.dart';
part 'src/encoding/bech32_encoder.dart';
part 'src/encoding/hex_encoder.dart';
part 'src/encoding/base16_encoder.dart';
6 changes: 3 additions & 3 deletions lib/src/authenticated_encryption/public.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Box extends BoxBase {

ByteList get sharedKey => this;

static const decoder = HexCoder.instance;
static const decoder = Base16Encoder.instance;

@override
Encoder get encoder => decoder;
Expand Down Expand Up @@ -113,7 +113,7 @@ class SealedBox extends ByteList {
SealedBox._fromKeyPair(
AsymmetricPrivateKey? privateKey, AsymmetricPublicKey publicKey)
: _privateKey = privateKey,
super.fromList(publicKey.asTypedList);
super(publicKey);

factory SealedBox(AsymmetricKey key) {
if (key is AsymmetricPrivateKey) {
Expand All @@ -136,7 +136,7 @@ class SealedBox extends ByteList {
static const _macBytes = TweetNaCl.macBytes;
static const _sealBytes = _pubLength + _macBytes;

static const decoder = HexCoder.instance;
static const decoder = Base16Encoder.instance;

@override
Encoder get encoder => decoder;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/authenticated_encryption/secret.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class SecretBox extends BoxBase {
static const keyLength = TweetNaCl.keyLength;
static const macBytes = TweetNaCl.macBytes;

static const decoder = HexCoder.instance;
static const decoder = Base16Encoder.instance;

@override
Encoder get encoder => decoder;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
part of pinenacl.encoding;

class HexCoder implements Encoder {
const HexCoder._singleton();
static const HexCoder instance = HexCoder._singleton();
class Base16Encoder implements Encoder {
const Base16Encoder._singleton();
static const Base16Encoder instance = Base16Encoder._singleton();

static const _alphabet = '0123456789abcdef';
static const _hexMap = <String, int>{
Expand Down
Loading

0 comments on commit 2b11d35

Please sign in to comment.