Skip to content

Commit

Permalink
fix keyring and key pair
Browse files Browse the repository at this point in the history
  • Loading branch information
justkawal committed Dec 4, 2023
1 parent c011cb6 commit 949c5ba
Show file tree
Hide file tree
Showing 22 changed files with 328 additions and 148 deletions.
8 changes: 8 additions & 0 deletions packages/polkadart_keyring/example/example.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'dart:typed_data';

import 'package:polkadart_keyring/polkadart_keyring.dart';

void main() {
KeyPair.ed25519.fromSeed(
Uint8List.fromList('12345678901234567890123456789012'.codeUnits));
}
6 changes: 6 additions & 0 deletions packages/polkadart_keyring/lib/polkadart_keyring.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
library polkadart_keyring;

import 'dart:convert';
import 'dart:typed_data';
import 'package:substrate_bip39/substrate_bip39.dart';
import 'package:ed25519_edwards/ed25519_edwards.dart' as ed;
import 'package:ss58/ss58.dart';
import 'package:sr25519/sr25519.dart' as sr25519;
import 'package:merlin/merlin.dart' as merlin;

part 'src/keyring.dart';
part 'src/keypair.dart';
part 'src/pairs.dart';
part 'src/extensions.dart';
part 'src/ed25519.dart';
part 'src/sr25519.dart';
85 changes: 85 additions & 0 deletions packages/polkadart_keyring/lib/src/ed25519.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
part of polkadart_keyring;

class Ed25519KeyPair extends KeyPair {
late ed.PublicKey _publicKey;
late ed.PrivateKey _privateKey;
bool _locked = false;

Ed25519KeyPair() : super(KeyPairType.ed25519);

@override
KeyPair fromSeed(Uint8List seed) {
_privateKey = ed.newKeyFromSeed(seed);
_publicKey = ed.public(_privateKey);
return this;
}

@override
Future<KeyPair> fromMnemonic(String mnemonic, [String? password]) async {
final seed =
await SubstrateBip39.ed25519.seedFromUri(mnemonic, password: password);
return KeyPair.ed25519.fromSeed(Uint8List.fromList(seed));
}

@override
Uint8List sign(Uint8List message) {
if (_locked) {
throw Exception('KeyPair is locked. Unlock it before signing.');
}
return ed.sign(_privateKey, message);
}

@override
bool verify(Uint8List message, Uint8List signature) {
return ed.verify(_publicKey, message, signature);
}

@override
String get address {
return Address(prefix: 42, pubkey: bytes).encode();
}

@override
Future<void> unlockFromMemonic(String mnemonic, [String? password]) async {
final seed =
await SubstrateBip39.ed25519.seedFromUri(mnemonic, password: password);
_unlock(ed.newKeyFromSeed(Uint8List.fromList(seed)));
}

@override
void unlockFromSeed(Uint8List seed) {
_unlock(ed.newKeyFromSeed(seed));
}

void _unlock(ed.PrivateKey privateKey) {
if (ed.public(privateKey).bytes.toString() != bytes.toString()) {
throw Exception('Public_Key_Mismatch: Invalid seed for given KeyPair.');
}
_privateKey = privateKey;
_locked = false;
}

@override
void lock() {
_isLocked = true;
_privateKey = ed.PrivateKey(Uint8List(0));
}

@override
Uint8List get bytes => Uint8List.fromList(_publicKey.bytes);

///
/// Returns `true` if the `KeyPair` matches with the other object.
@override
bool operator ==(Object other) {
if (other is KeyPair) {
return bytes == other.bytes;
}
return false;
}

///
/// Returns the hash code of the `KeyPair`.
@override
int get hashCode => bytes.hashCode;
}
10 changes: 10 additions & 0 deletions packages/polkadart_keyring/lib/src/extensions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
part of polkadart_keyring;

/// Represents a cryptographic key pair type for signing and verifying data.
enum KeyPairType {
/// Ed25519 key pair type.
ed25519,

/// Sr25519 key pair type.
sr25519,
}
132 changes: 46 additions & 86 deletions packages/polkadart_keyring/lib/src/keypair.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ part of polkadart_keyring;
/// includes a method to obtain the Substrate address encoded in SS58 format.
///
/// Example usages are provided for each function below.
class KeyPair {
late ed.PublicKey publicKey;
late ed.PrivateKey _privateKey;
bool _locked = false;
abstract class KeyPair {
static final ed25519 = Ed25519KeyPair();
static final sr25519 = Sr25519KeyPair();

final KeyPairType keyPairType;
late bool _isLocked;

/// constructor
KeyPair(this.keyPairType);

Uint8List get bytes;

/// Create a new `KeyPair` from a given seed.
///
Expand All @@ -21,10 +28,7 @@ class KeyPair {
/// final seed = Uint8List(32); // Replace with your actual seed
/// final keyPair = KeyPair.fromSeed(seed);
/// ```
KeyPair.fromSeed(Uint8List seed) {
_privateKey = ed.newKeyFromSeed(seed);
publicKey = ed.public(_privateKey);
}
KeyPair fromSeed(Uint8List seed);

/// Generate a `KeyPair` from a BIP39 mnemonic.
///
Expand All @@ -36,10 +40,7 @@ class KeyPair {
/// final mnemonic = "your mnemonic phrase"; // Replace with your actual mnemonic
/// final keyPair = await KeyPair.fromMnemonic(mnemonic);
/// ```
static Future<KeyPair> fromMnemonic(String mnemonic) async {
final seed = await SubstrateBip39.ed25519.seedFromUri(mnemonic);
return KeyPair.fromSeed(Uint8List.fromList(seed));
}
Future<KeyPair> fromMnemonic(String mnemonic, [String? password]);

/// Sign a given message with the private key.
///
Expand All @@ -51,12 +52,7 @@ class KeyPair {
/// final message = Uint8List.fromList([1, 2, 3, 4, 5]);
/// final signature = keyPair.sign(message);
/// ```
Uint8List sign(Uint8List message) {
if (_locked) {
throw Exception('KeyPair is locked. Unlock it before signing.');
}
return ed.sign(_privateKey, message);
}
Uint8List sign(Uint8List message);

/// Verify a message's signature using the public key.
///
Expand All @@ -71,49 +67,22 @@ class KeyPair {
/// final isVerified = keyPair.verify(message, signature);
/// print('Signature Verification: $isVerified');
/// ```
bool verify(Uint8List message, Uint8List signature) {
return ed.verify(publicKey, message, signature);
}

/// Get the Substrate address encoded in SS58 format.
///
/// This method uses the SS58 package to encode the public key with a default
/// prefix of 42.
///
/// Example:
/// ```dart
/// final keyPair = KeyPair.fromSeed(seed); // Replace with your actual seed
/// print('Substrate Address: ${keyPair.address}');
/// ```
String get address {
return Address(prefix: 42, pubkey: Uint8List.fromList(publicKey.bytes))
.encode();
}

///
/// Returns `true` if the `KeyPair` is locked.
///
/// Example:
/// ```dart
/// final keyPair = KeyPair.fromSeed(seed); // Replace with your actual seed
/// keyPair.lock();
/// print('Is locked: ${keyPair.isLocked}');
/// ```
bool get isLocked => _locked;
bool verify(Uint8List message, Uint8List signature);

/// Add lock functionality to a `KeyPair`.
/// Unlock a `KeyPair` from a given [seed].
///
/// This method locks the `KeyPair` by removing the private key.
/// This method unlocks the `KeyPair` by adding the private key.
///
/// Example:
/// ```dart
/// final seed = Uint8List(32); // Replace with your actual seed
/// final keyPair = KeyPair.fromSeed(seed);
/// keyPair.lock();
/// keyPair.sign(message); // Throws an error
/// keyPair.unlockFromSeed(seed);
/// keyPair.sign(message); // Works
/// ```
void lock() {
_privateKey = ed.PrivateKey(Uint8List(32));
_locked = true;
}
void unlockFromSeed(Uint8List seed);

/// Unlock a `KeyPair` from a given BIP39 mnemonic.
///
Expand All @@ -128,48 +97,39 @@ class KeyPair {
/// keyPair.unlockFromMemonic(mnemonic);
/// keyPair.sign(message); // Works
/// ```
Future<void> unlockFromMemonic(String mnemonic) async {
final seed = await SubstrateBip39.ed25519.seedFromUri(mnemonic);
_unlock(ed.newKeyFromSeed(Uint8List.fromList(seed)));
}
Future<void> unlockFromMemonic(String mnemonic, [String? password]);

/// Unlock a `KeyPair` from a given [seed].
/// Get the Substrate address encoded in SS58 format.
///
/// This method unlocks the `KeyPair` by adding the private key.
/// This method uses the SS58 package to encode the public key with a default
/// prefix of 42.
///
/// Example:
/// ```dart
/// final keyPair = KeyPair.fromSeed(seed); // Replace with your actual seed
/// print('Substrate Address: ${keyPair.address}');
/// ```
String get address;

/// Add lock functionality to a `KeyPair`.
///
/// This method locks the `KeyPair` by removing the private key.
///
/// Example:
/// ```dart
/// final seed = Uint8List(32); // Replace with your actual seed
/// final keyPair = KeyPair.fromSeed(seed);
/// keyPair.lock();
/// keyPair.sign(message); // Throws an error
/// keyPair.unlockFromSeed(seed);
/// keyPair.sign(message); // Works
/// ```
void unlockFromSeed(Uint8List seed) {
_unlock(ed.newKeyFromSeed(seed));
}

void _unlock(ed.PrivateKey privateKey) {
if (ed.public(privateKey).bytes.toString() != publicKey.bytes.toString()) {
throw Exception('Public_Key_Mismatch: Invalid seed for given KeyPair.');
}
_privateKey = privateKey;
_locked = false;
}
void lock();

///
/// Returns `true` if the `KeyPair` matches with the other object.
@override
bool operator ==(Object other) {
if (other is KeyPair) {
return publicKey.bytes == other.publicKey.bytes;
}
return false;
}

/// Returns `true` if the `KeyPair` is locked.
///
/// Returns the hash code of the `KeyPair`.
@override
int get hashCode => publicKey.bytes.hashCode;
/// Example:
/// ```dart
/// final keyPair = KeyPair.fromSeed(seed); // Replace with your actual seed
/// keyPair.lock();
/// print('Is locked: ${keyPair.isLocked}');
/// ```
bool get isLocked => _isLocked;
}
14 changes: 9 additions & 5 deletions packages/polkadart_keyring/lib/src/keyring.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ class Keyring {
/// final mnemonic = "your mnemonic phrase";
/// final keyPair = await keyring.createKeyPairFromMnemonic(mnemonic, addToPairs: true);
/// ```
Future<KeyPair> createKeyPairFromMnemonic(String mnemonic,
Future<KeyPair> createKeyPairFromMnemonic(String mnemonic, KeyPairType type,
{bool addToPairs = false}) async {
final pair = await KeyPair.fromMnemonic(mnemonic);
late KeyPair pair;

if (type == KeyPairType.ed25519) {
pair = await KeyPair.ed25519.fromMnemonic(mnemonic);
} else {
pair = await KeyPair.sr25519.fromMnemonic(mnemonic);
}
if (addToPairs) {
pairs.add(pair);
}
Expand Down Expand Up @@ -177,9 +183,7 @@ class Keyring {
/// final publicKeys = keyring.publicKeys;
/// ```
List<List<int>> get publicKeys {
return pairs.all
.map((pair) => List<int>.from(pair.publicKey.bytes))
.toList();
return pairs.all.map((pair) => List<int>.from(pair.bytes)).toList();
}

/// Get all addresses in the keyring.
Expand Down
2 changes: 1 addition & 1 deletion packages/polkadart_keyring/lib/src/pairs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ class Pairs {

/// Get a list of all public keys from the collection.
List<List<int>> get publicKeys {
return all.map((pair) => pair.publicKey.bytes).toList();
return all.map((pair) => pair.bytes).toList();
}

/// Get a list of all addresses from the collection.
Expand Down
Loading

0 comments on commit 949c5ba

Please sign in to comment.