#[cfg(feature = "crypto-full")]
#[strum_discriminants(strum(props(Arity = "6", Name = "$crypto_data_decrypt")))]
CryptoDataDecrypt,
- #[cfg(feature = "crypto-full")]
- #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign")))]
- Ed25519Sign,
- #[cfg(feature = "crypto-full")]
- #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify")))]
- Ed25519Verify,
- #[cfg(feature = "crypto-full")]
- #[strum_discriminants(strum(props(Arity = "1", Name = "$ed25519_new_keypair")))]
- Ed25519NewKeyPair,
- #[cfg(feature = "crypto-full")]
- #[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_keypair_public_key")))]
- Ed25519KeyPairPublicKey,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_sign_raw")))]
+ Ed25519SignRaw,
+ #[strum_discriminants(strum(props(Arity = "4", Name = "$ed25519_verify_raw")))]
+ Ed25519VerifyRaw,
+ #[strum_discriminants(strum(props(Arity = "2", Name = "$ed25519_seed_to_public_key")))]
+ Ed25519SeedToPublicKey,
#[strum_discriminants(strum(props(Arity = "2", Name = "$first_non_octet")))]
FirstNonOctet,
#[strum_discriminants(strum(props(Arity = "3", Name = "$load_html")))]
&Instruction::CallFlushTermQueue |
&Instruction::CallRemoveModuleExports |
&Instruction::CallAddNonCountedBacktracking |
- &Instruction::CallPopCount => {
+ &Instruction::CallPopCount |
+ &Instruction::CallEd25519SignRaw |
+ &Instruction::CallEd25519VerifyRaw |
+ &Instruction::CallEd25519SeedToPublicKey => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)])
}
//
#[cfg(feature = "crypto-full")]
&Instruction::CallCryptoDataEncrypt |
- &Instruction::CallCryptoDataDecrypt |
- &Instruction::CallEd25519Sign |
- &Instruction::CallEd25519Verify |
- &Instruction::CallEd25519NewKeyPair |
- &Instruction::CallEd25519KeyPairPublicKey => {
+ &Instruction::CallCryptoDataDecrypt => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("call"), [atom(name), fixnum(arity)])
}
&Instruction::ExecuteFlushTermQueue |
&Instruction::ExecuteRemoveModuleExports |
&Instruction::ExecuteAddNonCountedBacktracking |
- &Instruction::ExecutePopCount => {
+ &Instruction::ExecutePopCount |
+ &Instruction::ExecuteEd25519SignRaw |
+ &Instruction::ExecuteEd25519VerifyRaw |
+ &Instruction::ExecuteEd25519SeedToPublicKey => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)])
}
//
#[cfg(feature = "crypto-full")]
&Instruction::ExecuteCryptoDataEncrypt |
- &Instruction::ExecuteCryptoDataDecrypt |
- &Instruction::ExecuteEd25519Sign |
- &Instruction::ExecuteEd25519Verify |
- &Instruction::ExecuteEd25519NewKeyPair |
- &Instruction::ExecuteEd25519KeyPairPublicKey => {
+ &Instruction::ExecuteCryptoDataDecrypt => {
let (name, arity) = self.to_name_and_arity();
functor!(atom!("execute"), [atom(name), fixnum(arity)])
}
crypto_password_hash/3, % +Password, -Hash, +Options
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
+ ed25519_seed_keypair/2, % +Seed, -KeyPair
ed25519_new_keypair/1, % -KeyPair
ed25519_keypair_public_key/2, % +KeyPair, +PublicKey
ed25519_sign/4, % +KeyPair, +Data, -Signature, +Options
===============================
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
+%% ed25519_seed_keypair(+Seed, -Pair)
+%
+% Use Seed to deterministically generate an Ed25519 key pair Pair, a
+% list of characters. Seed must be a list of 32 bytes. It can be
+% chosen at random (using for example `crypto_n_random_bytes/2`) or
+% derived from input keying material (IKM) using for example
+% `crypto_data_hkdf/4`. The pair contains the private key and must be
+% kept absolutely secret. Pair can be used for signing. Its public
+% key can be obtained with `ed25519_keypair_public_key/2`.
+
+ed25519_seed_keypair(Seed, Pair) :-
+ must_be_bytes(Seed, ed25519_keypair_from_seed/2),
+ length(Seed, 32),
+ '$ed25519_seed_to_public_key'(Seed, Public),
+ maplist(char_code, Public, PublicBytes),
+ phrase(([0x30,81], % a sequence of 81 bytes follows
+ [2,1], % the integer 1 denoting version 2 (awesome design!)
+ [1], % the public key is also present
+ [48,5], % an element of 5 bytes follows
+ [6,3,43,101,112], % OID of Ed25519
+ [4,34], % an octet string of 34 bytes follows
+ [4,32], % an octet string of 32 bytes follows
+ seq(Seed), % the seed is the private key
+ [129,33],
+ [0], % 32 bytes is divisible by 8
+ seq(PublicBytes)), ASN1),
+ maplist(char_code, Pair, ASN1).
+
%% ed25519_new_keypair(-Pair)
%
% Yields a new Ed25519 key pair Pair, a list of characters. The
% with `ed25519_keypair_public_key/2`.
ed25519_new_keypair(Pair) :-
- '$ed25519_new_keypair'(Pair).
+ crypto_n_random_bytes(32, Bytes),
+ ed25519_seed_keypair(Bytes, Pair).
%% ed25519_keypair_public_key(+Pair, -PublicKey)
%
% The public key is represented as a list of characters.
ed25519_keypair_public_key(Pair, PublicKey) :-
- must_be_octet_chars(Pair, ed25519_keypair_public_key),
- '$ed25519_keypair_public_key'(Pair, PublicKey).
+ must_be_octet_chars(Pair, ed25519_keypair_public_key/2),
+ reverse(Pair, RPs),
+ length(RPublicKey, 32),
+ phrase((seq(RPublicKey),...), RPs),
+ reverse(RPublicKey, PublicKey).
%% ed25519_sign(+Key, +Data, -Signature, +Options)
%
% PKCS#8 v2 format as generated by `ed25519_new_keypair/1`. Sign Data
% with Key, yielding Signature as a list of hexadecimal characters.
-ed25519_sign(Key, Data0, Signature, Options) :-
- must_be_octet_chars(Key, ed25519_sign),
+ed25519_sign(KeyPair, Data0, Signature, Options) :-
+ must_be_octet_chars(KeyPair, ed25519_sign/4),
+ length(Prefix, 16),
+ length(PrivateKeyChars, 32),
+ phrase((seq(Prefix),seq(PrivateKeyChars),...), KeyPair),
+ maplist(char_code, PrivateKeyChars, PrivateKey),
options_data_chars(Options, Data0, Data, Encoding),
- '$ed25519_sign'(Key, Data, Encoding, Signature0),
+ '$ed25519_sign_raw'(PrivateKey, Data, Encoding, Signature0),
hex_bytes(Signature, Signature0).
%% ed25519_verify(+Key, +Data, +Signature, +Options)
% which treats Data as a list of raw bytes.
ed25519_verify(Key, Data0, Signature0, Options) :-
- must_be_octet_chars(Key, ed25519_verify),
+ must_be_octet_chars(Key, ed25519_verify/4),
options_data_chars(Options, Data0, Data, Encoding),
hex_bytes(Signature0, Signature),
- '$ed25519_verify'(Key, Data, Encoding, Signature).
+ '$ed25519_verify_raw'(Key, Data, Encoding, Signature).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
X25519: ECDH key exchange over Curve25519
self.crypto_curve_scalar_mult();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
- #[cfg(feature = "crypto-full")]
- &Instruction::CallEd25519Sign => {
- self.ed25519_sign();
- step_or_fail!(self, self.machine_st.p += 1);
- }
- #[cfg(feature = "crypto-full")]
- &Instruction::ExecuteEd25519Sign => {
- self.ed25519_sign();
- step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
- }
- #[cfg(feature = "crypto-full")]
- &Instruction::CallEd25519Verify => {
- self.ed25519_verify();
+ &Instruction::CallEd25519SignRaw => {
+ self.ed25519_sign_raw();
step_or_fail!(self, self.machine_st.p += 1);
}
- #[cfg(feature = "crypto-full")]
- &Instruction::ExecuteEd25519Verify => {
- self.ed25519_verify();
+ &Instruction::ExecuteEd25519SignRaw => {
+ self.ed25519_sign_raw();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
- #[cfg(feature = "crypto-full")]
- &Instruction::CallEd25519NewKeyPair => {
- self.ed25519_new_key_pair();
+ &Instruction::CallEd25519VerifyRaw => {
+ self.ed25519_verify_raw();
step_or_fail!(self, self.machine_st.p += 1);
}
- #[cfg(feature = "crypto-full")]
- &Instruction::ExecuteEd25519NewKeyPair => {
- self.ed25519_new_key_pair();
+ &Instruction::ExecuteEd25519VerifyRaw => {
+ self.ed25519_verify_raw();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
- #[cfg(feature = "crypto-full")]
- &Instruction::CallEd25519KeyPairPublicKey => {
- self.ed25519_key_pair_public_key();
+ &Instruction::CallEd25519SeedToPublicKey => {
+ self.ed25519_seed_to_public_key();
step_or_fail!(self, self.machine_st.p += 1);
}
- #[cfg(feature = "crypto-full")]
- &Instruction::ExecuteEd25519KeyPairPublicKey => {
- self.ed25519_key_pair_public_key();
+ &Instruction::ExecuteEd25519SeedToPublicKey => {
+ self.ed25519_seed_to_public_key();
step_or_fail!(self, self.machine_st.p = self.machine_st.cp);
}
&Instruction::CallCurve25519ScalarMult => {
use ring::{digest, hkdf, pbkdf2};
#[cfg(feature = "crypto-full")]
-use ring::{
- aead,
- signature::{self, KeyPair},
-};
+use ring::aead;
use ripemd160::{Digest, Ripemd160};
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
-use crrl::{secp256k1, x25519};
+use crrl::{ed25519, secp256k1, x25519};
#[cfg(feature = "tls")]
use native_tls::{Identity, TlsAcceptor, TlsConnector};
unify!(self.machine_st, self.machine_st.registers[4], uncompressed);
}
- #[cfg(feature = "crypto-full")]
#[inline(always)]
- pub(crate) fn ed25519_new_key_pair(&mut self) {
- let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap();
- let complete_string = self.u8s_to_string(pkcs8_bytes.as_ref());
-
- unify!(
- self.machine_st,
- self.machine_st.registers[1],
- complete_string
- )
- }
-
- #[cfg(feature = "crypto-full")]
- #[inline(always)]
- pub(crate) fn ed25519_key_pair_public_key(&mut self) {
- let bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+ pub(crate) fn ed25519_seed_to_public_key(&mut self) {
+ let stub_gen = || functor_stub(atom!("ed25519_seed_keypair"), 2);
+ let seed_bytes = self
+ .machine_st
+ .integers_to_bytevec(self.machine_st.registers[1], stub_gen);
- let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
- Ok(kp) => kp,
- _ => {
- self.machine_st.fail = true;
- return;
- }
- };
+ let skey = ed25519::PrivateKey::from_seed(&seed_bytes);
- let complete_string = self.u8s_to_string(key_pair.public_key().as_ref());
+ let complete_string = self.u8s_to_string(skey.public_key.encoded.as_ref());
unify!(
self.machine_st,
);
}
- #[cfg(feature = "crypto-full")]
#[inline(always)]
- pub(crate) fn ed25519_sign(&mut self) {
- let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+ pub(crate) fn ed25519_sign_raw(&mut self) {
+ let stub_gen = || functor_stub(atom!("ed25519_sign"), 4);
+ let seed_bytes = self
+ .machine_st
+ .integers_to_bytevec(self.machine_st.registers[1], stub_gen);
+
+ let skey = ed25519::PrivateKey::from_seed(&seed_bytes);
+
let encoding = cell_as_atom!(self.deref_register(3));
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
- let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&key) {
- Ok(kp) => kp,
- _ => {
- self.machine_st.fail = true;
- return;
- }
- };
-
- let sig = key_pair.sign(&data);
+ let sig = skey.sign_raw(&data);
let sig_list = heap_loc_as_cell!(iter_to_heap_list(
&mut self.machine_st.heap,
unify!(self.machine_st, self.machine_st.registers[4], sig_list);
}
- #[cfg(feature = "crypto-full")]
#[inline(always)]
- pub(crate) fn ed25519_verify(&mut self) {
- let key = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+ pub(crate) fn ed25519_verify_raw(&mut self) {
+ let key_bytes = self.string_encoding_bytes(self.machine_st.registers[1], atom!("octet"));
+ let pkey = ed25519::PublicKey::decode(&key_bytes).unwrap();
+
let encoding = cell_as_atom!(self.deref_register(3));
let data = self.string_encoding_bytes(self.machine_st.registers[2], encoding);
- let stub_gen = || functor_stub(atom!("ed25519_verify"), 5);
+
+ let stub_gen = || functor_stub(atom!("ed25519_verify"), 4);
+
let signature = self
.machine_st
.integers_to_bytevec(self.machine_st.registers[4], stub_gen);
- let peer_public_key = signature::UnparsedPublicKey::new(&signature::ED25519, &key);
-
- match peer_public_key.verify(&data, &signature) {
- Ok(_) => {}
- _ => {
- self.machine_st.fail = true;
- }
- }
+ self.machine_st.fail = !pkey.verify_raw(&signature, &data);
}
#[inline(always)]