ADDED: Public key signatures and signature verification with Ed25519
This commit is contained in:
@@ -380,6 +380,7 @@ The modules that ship with Scryer Prolog are also called
|
|||||||
* [`crypto`](src/prolog/lib/crypto.pl)
|
* [`crypto`](src/prolog/lib/crypto.pl)
|
||||||
Cryptographically secure random numbers and hashes, HMAC-based
|
Cryptographically secure random numbers and hashes, HMAC-based
|
||||||
key derivation (HKDF), password-based key derivation (PBKDF2),
|
key derivation (HKDF), password-based key derivation (PBKDF2),
|
||||||
|
public key signatures and signature verification with Ed25519,
|
||||||
authenticated encryption, and reasoning about elliptic curves.
|
authenticated encryption, and reasoning about elliptic curves.
|
||||||
|
|
||||||
To read contents of external files, use `phrase_from_file/2` from
|
To read contents of external files, use `phrase_from_file/2` from
|
||||||
|
|||||||
@@ -291,7 +291,9 @@ pub enum SystemClauseType {
|
|||||||
CryptoDataHKDF,
|
CryptoDataHKDF,
|
||||||
CryptoPasswordHash,
|
CryptoPasswordHash,
|
||||||
CryptoDataEncrypt,
|
CryptoDataEncrypt,
|
||||||
CryptoDataDecrypt
|
CryptoDataDecrypt,
|
||||||
|
Ed25519Sign,
|
||||||
|
Ed25519Verify
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SystemClauseType {
|
impl SystemClauseType {
|
||||||
@@ -480,6 +482,8 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
|
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
|
||||||
&SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
|
&SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
|
||||||
&SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"),
|
&SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"),
|
||||||
|
&SystemClauseType::Ed25519Sign => clause_name!("$ed25519_sign"),
|
||||||
|
&SystemClauseType::Ed25519Verify => clause_name!("$ed25519_verify"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,6 +652,8 @@ impl SystemClauseType {
|
|||||||
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
||||||
("$crypto_data_encrypt", 5) => Some(SystemClauseType::CryptoDataEncrypt),
|
("$crypto_data_encrypt", 5) => Some(SystemClauseType::CryptoDataEncrypt),
|
||||||
("$crypto_data_decrypt", 5) => Some(SystemClauseType::CryptoDataDecrypt),
|
("$crypto_data_decrypt", 5) => Some(SystemClauseType::CryptoDataDecrypt),
|
||||||
|
("$ed25519_sign", 3) => Some(SystemClauseType::Ed25519Sign),
|
||||||
|
("$ed25519_verify", 3) => Some(SystemClauseType::Ed25519Verify),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
and strings have the advantage that the atom table remains unmodified.
|
and strings have the advantage that the atom table remains unmodified.
|
||||||
|
|
||||||
Especially for cryptographic applications, it as an advantage that
|
Especially for cryptographic applications, it as an advantage that
|
||||||
using strings leaves little trace of what was processed in the system,
|
using strings leaves little trace of what was processed in the system.
|
||||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
:- module(crypto,
|
:- module(crypto,
|
||||||
@@ -21,6 +21,8 @@
|
|||||||
crypto_password_hash/3, % +Password, -Hash, +Options
|
crypto_password_hash/3, % +Password, -Hash, +Options
|
||||||
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
|
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
|
||||||
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
|
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
|
||||||
|
ed25519_sign/4, % +PrivateKey, +Data, -Signature, +Options
|
||||||
|
ed25519_verify/4, % +PublicKey, +Data, -Signature, +Options
|
||||||
crypto_name_curve/2, % +Name, -Curve
|
crypto_name_curve/2, % +Name, -Curve
|
||||||
crypto_curve_order/2, % +Curve, -Order
|
crypto_curve_order/2, % +Curve, -Order
|
||||||
crypto_curve_generator/2, % +Curve, -Generator
|
crypto_curve_generator/2, % +Curve, -Generator
|
||||||
@@ -624,6 +626,44 @@ encoding_bytes(utf8, Cs, Bs) :-
|
|||||||
; domain_error(encryption_encoding, Cs, crypto)
|
; domain_error(encryption_encoding, Cs, crypto)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
Digital signatures with Ed25519
|
||||||
|
===============================
|
||||||
|
|
||||||
|
ed25519_sign(+Key, +Data, -Signature, +Options)
|
||||||
|
|
||||||
|
Key and Data must be lists of characters. Key is a private key in
|
||||||
|
PKCS#8 (v1 or v2) DER format. Sign Data with Key, yielding
|
||||||
|
Signature as a list of hexadecimal characters.
|
||||||
|
|
||||||
|
|
||||||
|
ed25519_verify(+Key, +Data, +Signature, +Options)
|
||||||
|
|
||||||
|
Key and Data must be lists of characters. Key is a public key in
|
||||||
|
PKCS#8 DER format. Succeeds if Data was signed with the private key
|
||||||
|
corresponding to Key, where Signature is a list of hexadecimal
|
||||||
|
characters as generated by ed25519_sign/4. Fails otherwise.
|
||||||
|
|
||||||
|
|
||||||
|
Currently, the only option for both predicates is:
|
||||||
|
|
||||||
|
- encoding(+Encoding)
|
||||||
|
The default encoding of Data is utf8. The alternative is octet,
|
||||||
|
which treats Data as a list of raw bytes.
|
||||||
|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||||
|
|
||||||
|
ed25519_sign(Key0, Data0, Signature, Options) :-
|
||||||
|
options_data_bytes(Options, Data0, Data),
|
||||||
|
encoding_bytes(octet, Key0, Key),
|
||||||
|
'$ed25519_sign'(Key, Data, Signature0),
|
||||||
|
hex_bytes(Signature, Signature0).
|
||||||
|
|
||||||
|
ed25519_verify(Key0, Data0, Signature0, Options) :-
|
||||||
|
options_data_bytes(Options, Data0, Data),
|
||||||
|
encoding_bytes(octet, Key0, Key),
|
||||||
|
hex_bytes(Signature0, Signature),
|
||||||
|
'$ed25519_verify'(Key, Data, Signature).
|
||||||
|
|
||||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
Modular multiplicative inverse.
|
Modular multiplicative inverse.
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ use crate::crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
|
|||||||
use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode};
|
use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode};
|
||||||
|
|
||||||
use ring::rand::{SecureRandom, SystemRandom};
|
use ring::rand::{SecureRandom, SystemRandom};
|
||||||
use ring::{digest,hkdf,pbkdf2,aead,error};
|
use ring::{digest,hkdf,pbkdf2,aead,error,signature};
|
||||||
use ripemd160::{Ripemd160, Digest};
|
use ripemd160::{Ripemd160, Digest};
|
||||||
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
|
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
|
||||||
use blake2::{Blake2s, Blake2b};
|
use blake2::{Blake2s, Blake2b};
|
||||||
@@ -5448,6 +5448,38 @@ impl MachineState {
|
|||||||
|
|
||||||
self.unify(self[temp_v!(5)], complete_string);
|
self.unify(self[temp_v!(5)], complete_string);
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::Ed25519Sign => {
|
||||||
|
let stub1 = MachineError::functor_stub(clause_name!("ed25519_sign"), 4);
|
||||||
|
let key = self.integers_to_bytevec(temp_v!(1), stub1);
|
||||||
|
let stub2 = MachineError::functor_stub(clause_name!("ed25519_sign"), 4);
|
||||||
|
let data = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||||
|
|
||||||
|
let key_pair = match signature::Ed25519KeyPair::from_pkcs8_maybe_unchecked(&key) {
|
||||||
|
Ok(kp) => { kp }
|
||||||
|
_ => { self.fail = true; return Ok(()); }
|
||||||
|
};
|
||||||
|
|
||||||
|
let sig = key_pair.sign(&data);
|
||||||
|
|
||||||
|
let sig_list =
|
||||||
|
Addr::HeapCell(self.heap.to_list(sig.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize)))));
|
||||||
|
|
||||||
|
self.unify(self[temp_v!(3)], sig_list);
|
||||||
|
}
|
||||||
|
&SystemClauseType::Ed25519Verify => {
|
||||||
|
let stub1 = MachineError::functor_stub(clause_name!("ed25519_verify"), 4);
|
||||||
|
let key = self.integers_to_bytevec(temp_v!(1), stub1);
|
||||||
|
let stub2 = MachineError::functor_stub(clause_name!("ed25519_verify"), 4);
|
||||||
|
let data = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||||
|
let stub3 = MachineError::functor_stub(clause_name!("ed25519_verify"), 4);
|
||||||
|
let signature = self.integers_to_bytevec(temp_v!(3), stub3);
|
||||||
|
|
||||||
|
let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
|
||||||
|
match peer_public_key.verify(&data, &signature) {
|
||||||
|
Ok(_) => { }
|
||||||
|
_ => { self.fail = true; return Ok(()); }
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return_from_clause!(self.last_call, self)
|
return_from_clause!(self.last_call, self)
|
||||||
|
|||||||
Reference in New Issue
Block a user