-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
29 changed files
with
697 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export 'kms.dart'; | ||
export 'key-providers/index.dart'; | ||
export 'store/index.dart'; | ||
export 'provider-helpers.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import "dart:typed_data"; | ||
|
||
import "package:encrypt/encrypt.dart"; | ||
import "package:polygonid_flutter_sdk/common/kms/index.dart"; | ||
import "package:polygonid_flutter_sdk/common/utils/big_int_extension.dart"; | ||
import "package:polygonid_flutter_sdk/common/utils/uint8_list_utils.dart"; | ||
import "package:web3dart/crypto.dart"; | ||
|
||
import "../../../identity/libs/bjj/eddsa_babyjub.dart"; | ||
|
||
/// Provider for Baby Jub Jub keys | ||
/// @public | ||
/// @class BjjProvider | ||
/// @implements implements IKeyProvider interface | ||
class BjjProvider implements IKeyProvider { | ||
/// key type that is handled by BJJ Provider | ||
/// @type {KmsKeyType} | ||
KmsKeyType get keyType => KmsKeyType.BabyJubJub; | ||
|
||
AbstractPrivateKeyStore keyStore; | ||
|
||
/// Creates an instance of BjjProvider. | ||
/// @param {KmsKeyType} keyType - kms key type | ||
/// @param {AbstractPrivateKeyStore} keyStore - key store for kms | ||
BjjProvider(KmsKeyType keyType, this.keyStore) { | ||
if (keyType != KmsKeyType.BabyJubJub) { | ||
throw Exception('Key type must be BabyJubJub'); | ||
} | ||
} | ||
|
||
/// generates a baby jub jub key from a seed phrase | ||
/// @param {Uint8List} seed - byte array seed | ||
/// @returns kms key identifier | ||
@override | ||
Future<KmsKeyId> newPrivateKeyFromSeed(Uint8List seed) async { | ||
final privateKey = PrivateKey(seed); | ||
|
||
final publicKey = privateKey.public(); | ||
|
||
final kmsId = KmsKeyId( | ||
type: keyType, | ||
id: keyPath(keyType, publicKey.hex()), | ||
); | ||
await keyStore.importKey(alias: kmsId.id, key: privateKey.hex()); | ||
|
||
return kmsId; | ||
} | ||
|
||
/// Gets public key by kmsKeyId | ||
/// | ||
/// @param {KmsKeyId} keyId - key identifier | ||
@override | ||
Future<String> publicKey(KmsKeyId keyId) async { | ||
final privateKey = await _privateKey(keyId); | ||
return privateKey.public().hex(); | ||
} | ||
|
||
/// signs prepared payload of size, | ||
/// with a key id | ||
/// | ||
/// @param {KmsKeyId} keyId - key identifier | ||
/// @param {Uint8List} data - data to sign (32 bytes) | ||
/// @returns Uint8List signature | ||
@override | ||
Future<Uint8List> sign( | ||
KmsKeyId keyId, | ||
Uint8List data, [ | ||
Map<String, dynamic>? opts, | ||
]) async { | ||
if (data.length != 32) { | ||
throw Exception('data to sign is too large'); | ||
} | ||
|
||
final i = bytesToUnsignedInt(data); | ||
if (!i.checkBigIntInField()) { | ||
throw Exception('data to sign is too large'); | ||
} | ||
final privateKey = await _privateKey(keyId); | ||
|
||
final signature = privateKey.sign(i); | ||
|
||
return Uint8ArrayUtils.uint8ListfromString(signature); | ||
} | ||
|
||
@override | ||
Future<bool> verify( | ||
Uint8List message, String signatureHex, KmsKeyId keyId) async { | ||
final publicKey = await this.publicKey(keyId); | ||
|
||
final bytes = hexToBytes(publicKey); | ||
final pbkey = PublicKey.newFromCompressed(bytesToUnsignedInt(bytes)); | ||
|
||
return pbkey.verify( | ||
Uint8ArrayUtils.uint8ListToString(message), | ||
Signature.newFromCompressed(hexToBytes(signatureHex)), | ||
); | ||
} | ||
|
||
Future<PrivateKey> _privateKey(KmsKeyId keyId) async { | ||
final privateKeyHex = await keyStore.get(alias: keyId.id); | ||
|
||
return PrivateKey(decodeHexString(privateKeyHex)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import 'dart:typed_data'; | ||
|
||
import 'package:polygonid_flutter_sdk/common/kms/kms.dart'; | ||
import 'package:polygonid_flutter_sdk/common/kms/provider-helpers.dart'; | ||
import 'package:polygonid_flutter_sdk/common/kms/store/abstract-key-store.dart'; | ||
import 'package:polygonid_flutter_sdk/common/kms/store/types.dart'; | ||
import 'package:polygonid_flutter_sdk/common/utils/uint8_list_utils.dart'; | ||
import 'package:web3dart/crypto.dart'; | ||
import 'package:ed25519_edwards/ed25519_edwards.dart' as ed25519; | ||
|
||
/// Provider for Ed25519 keys | ||
/// @public | ||
/// @class Ed25519Provider | ||
/// @implements IKeyProvider interface | ||
class Ed25519Provider implements IKeyProvider { | ||
final KmsKeyType keyType; | ||
final AbstractPrivateKeyStore _keyStore; | ||
|
||
/// Creates an instance of Ed25519Provider. | ||
/// @param {KmsKeyType} keyType - kms key type | ||
/// @param {AbstractPrivateKeyStore} keyStore - key store for kms | ||
Ed25519Provider(this.keyType, this._keyStore); | ||
|
||
/// generates a ed25519 key from a seed phrase | ||
/// @param {Uint8List} seed - byte array seed | ||
/// @returns {Future<KmsKeyId>} kms key identifier | ||
@override | ||
Future<KmsKeyId> newPrivateKeyFromSeed(Uint8List seed) async { | ||
if (seed.length != 32) { | ||
throw Exception('Seed should be 32 bytes'); | ||
} | ||
final publicKey = ed25519.PublicKey(seed); | ||
final kmsId = KmsKeyId( | ||
type: keyType, | ||
id: keyPath(keyType, bytesToHex(publicKey.bytes)), | ||
); | ||
|
||
await _keyStore.importKey( | ||
alias: kmsId.id, | ||
key: bytesToHex(seed), | ||
); | ||
|
||
return kmsId; | ||
} | ||
|
||
/// Gets public key by kmsKeyId | ||
/// @param {KmsKeyId} keyId - key identifier | ||
/// @returns {Future<String>} Public key as a hex String | ||
@override | ||
Future<String> publicKey(KmsKeyId keyId) async { | ||
final privateKeyHex = await _privateKey(keyId); | ||
final privateKey = ed25519.newKeyFromSeed(hexToBytes(privateKeyHex)); | ||
final publicKey = ed25519.public(privateKey); | ||
return bytesToHex(publicKey.bytes); | ||
} | ||
|
||
/// signs prepared payload of size, | ||
/// with a key id | ||
/// @param {KmsKeyId} keyId - key identifier | ||
/// @param {Uint8List} digest - data to sign (32 bytes) | ||
/// @returns {Future<Uint8List>} signature | ||
@override | ||
Future<Uint8List> sign( | ||
KmsKeyId keyId, | ||
Uint8List digest, [ | ||
Map<String, dynamic>? opts, | ||
]) async { | ||
final privateKeyHex = await _privateKey(keyId); | ||
final privateKey = ed25519.newKeyFromSeed(hexToBytes(privateKeyHex)); | ||
|
||
return ed25519.sign(privateKey, digest); | ||
} | ||
|
||
/// Verifies a signature for the given message and key identifier. | ||
/// @param digest - The message to verify the signature against. | ||
/// @param signatureHex - The signature to verify, as a hexadecimal String. | ||
/// @param keyId - The key identifier to use for verification. | ||
/// @returns A Future that resolves to a boolean indicating whether the signature is valid. | ||
Future<bool> verify( | ||
Uint8List digest, String signatureHex, KmsKeyId keyId) async { | ||
final publicKeyHex = await this.publicKey(keyId); | ||
final publicKey = ed25519.PublicKey(hexToBytes(publicKeyHex)); | ||
|
||
return ed25519.verify( | ||
publicKey, | ||
digest, | ||
hexToBytes(signatureHex), | ||
); | ||
} | ||
|
||
/// Retrieves the private key for a given keyId from the key store. | ||
/// @param {KmsKeyId} keyId - The identifier of the key to retrieve. | ||
/// @returns {Future<String>} The private key associated with the keyId. | ||
Future<String> _privateKey(KmsKeyId keyId) async { | ||
return _keyStore.get(alias: keyId.id); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export 'bjj-provider.dart'; | ||
export 'ed25519-provider.dart'; | ||
export 'secp256k1-provider.dart'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import 'dart:typed_data'; | ||
|
||
import 'package:crypto/crypto.dart'; | ||
import 'package:polygonid_flutter_sdk/common/kms/kms.dart'; | ||
import 'package:polygonid_flutter_sdk/common/kms/provider-helpers.dart'; | ||
import 'package:polygonid_flutter_sdk/common/kms/store/abstract-key-store.dart'; | ||
import 'package:polygonid_flutter_sdk/common/kms/store/types.dart'; | ||
import 'package:web3dart/crypto.dart'; | ||
import 'package:secp256k1/secp256k1.dart' as secp256k1; | ||
|
||
/// Provider for Secp256k1 | ||
/// @public | ||
/// @class Secp256k1Provider | ||
/// @implements implements IKeyProvider interface | ||
class Sec256k1Provider implements IKeyProvider { | ||
/// key type that is handled by BJJ Provider | ||
/// @type {KmsKeyType} | ||
final KmsKeyType keyType; | ||
final AbstractPrivateKeyStore _keyStore; | ||
|
||
/// Creates an instance of Sec256k1Provider. | ||
/// @param {KmsKeyType} keyType - kms key type | ||
/// @param {AbstractPrivateKeyStore} keyStore - key store for kms | ||
Sec256k1Provider(this.keyType, this._keyStore) { | ||
if (keyType != KmsKeyType.Secp256k1) { | ||
throw Exception('Key type must be Secp256k1'); | ||
} | ||
} | ||
|
||
/// generates a baby jub jub key from a seed phrase | ||
/// @param {Uint8List} seed - byte array seed | ||
/// @returns kms key identifier | ||
@override | ||
Future<KmsKeyId> newPrivateKeyFromSeed(Uint8List seed) async { | ||
if (seed.length != 32) { | ||
throw Exception('Seed should be 32 bytes'); | ||
} | ||
final privateKey = secp256k1.PrivateKey.fromHex(bytesToHex(seed)); | ||
final publicKey = privateKey.publicKey; | ||
|
||
final kmsId = KmsKeyId( | ||
type: keyType, | ||
id: keyPath(keyType, publicKey.toHex()), | ||
); | ||
|
||
await _keyStore.importKey( | ||
alias: kmsId.id, | ||
key: bytesToHex(seed).padLeft(64, '0'), | ||
); | ||
|
||
return kmsId; | ||
} | ||
|
||
/// Gets public key by kmsKeyId | ||
/// | ||
/// @param {KmsKeyId} keyId - key identifier | ||
@override | ||
Future<String> publicKey(KmsKeyId keyId) async { | ||
final privateKeyHex = await _privateKey(keyId); | ||
final privateKey = secp256k1.PrivateKey.fromHex(privateKeyHex); | ||
final publicKey = privateKey.publicKey; | ||
return publicKey.toHex(); // 04 + x + y (uncompressed key) | ||
} | ||
|
||
/// Signs the given data using the private key associated with the specified key identifier. | ||
/// @param keyId - The key identifier to use for signing. | ||
/// @param data - The data to sign. | ||
/// @param opts - Signing options, such as the algorithm to use. | ||
/// @returns A Future that resolves to the signature as a Uint8List. | ||
@override | ||
Future<Uint8List> sign( | ||
KmsKeyId keyId, | ||
Uint8List data, [ | ||
Map<String, dynamic>? opts, | ||
]) async { | ||
final privateKeyHex = await _privateKey(keyId); | ||
final privateKey = secp256k1.PrivateKey.fromHex(privateKeyHex); | ||
|
||
final signature = privateKey.signature(bytesToHex(data)); | ||
|
||
final signatureBytes = Uint8List(64); | ||
final rBytes = hexToBytes(signature.R.toRadixString(16).padLeft(32, '0')); | ||
signatureBytes.setRange(0, 32, rBytes); | ||
final sBytes = hexToBytes(signature.S.toRadixString(16).padLeft(32, '0')); | ||
signatureBytes.setRange(32, 64, sBytes); | ||
|
||
// final signatureBase64 = await ES256KSigner( | ||
// hexToBytes(privateKeyHex), opts?["alg"] == 'ES256K-R')(data); | ||
// | ||
// if (signatureBase64.runtimeType != String) { | ||
// throw Exception('signatureBase64 must be a String'); | ||
// } | ||
|
||
return signatureBytes; | ||
} | ||
|
||
/// Verifies a signature for the given message and key identifier. | ||
/// @param message - The message to verify the signature against. | ||
/// @param signatureHex - The signature to verify, as a hexadecimal String. | ||
/// @param keyId - The key identifier to use for verification. | ||
/// @returns A Future that resolves to a boolean indicating whether the signature is valid. | ||
@override | ||
Future<bool> verify( | ||
Uint8List message, | ||
String signatureHex, | ||
KmsKeyId keyId, | ||
) async { | ||
final publicKeyHex = await this.publicKey(keyId); | ||
|
||
final publicKey = secp256k1.PublicKey.fromHex(publicKeyHex); | ||
|
||
final signature = secp256k1.Signature.fromHexes( | ||
signatureHex.substring(0, signatureHex.length ~/ 2), | ||
signatureHex.substring(signatureHex.length ~/ 2, signatureHex.length), | ||
); | ||
|
||
return signature.verify( | ||
publicKey, | ||
bytesToHex(message), | ||
); | ||
} | ||
|
||
Future<String> _privateKey(KmsKeyId keyId) async { | ||
return _keyStore.get(alias: keyId.id); | ||
} | ||
} |
Oops, something went wrong.