Merge branch 'master' of https://github.com/mthom/rusty-wam
This commit is contained in:
41
.travis.yml
41
.travis.yml
@@ -1,14 +1,31 @@
|
||||
language: rust
|
||||
rust:
|
||||
- stable
|
||||
- beta
|
||||
- nightly
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rust: nightly
|
||||
fast_finish: true
|
||||
cache: cargo
|
||||
os: linux
|
||||
dist: xenial
|
||||
|
||||
script:
|
||||
- cargo build --verbose --all
|
||||
- cargo test --verbose --all
|
||||
- cargo test --verbose --all --no-default-features --features num
|
||||
before_script:
|
||||
- cargo fetch
|
||||
|
||||
jobs:
|
||||
allow_failures:
|
||||
env:
|
||||
- CAN_FAIL=true
|
||||
include:
|
||||
- stage: "Stable: Build"
|
||||
rust: stable
|
||||
script: cargo rustc --verbose -- -D warnings
|
||||
name: "Build Stable"
|
||||
- stage: "Stable: Tests"
|
||||
rust: stable
|
||||
script: cargo test --verbose --all
|
||||
name: "Tests Stable"
|
||||
- stage: "Features"
|
||||
rust: stable
|
||||
script: cargo test --verbose --all --no-default-features --features num
|
||||
name: "num Tests"
|
||||
env: CAN_FAIL=true
|
||||
- stage: "Beta: Build"
|
||||
# - #
|
||||
rust: beta
|
||||
script: cargo rustc --verbose -- -D warnings
|
||||
name: "Build Beta"
|
||||
|
||||
@@ -380,7 +380,7 @@ The modules that ship with Scryer Prolog are also called
|
||||
* [`crypto`](src/prolog/lib/crypto.pl)
|
||||
Cryptographically secure random numbers and hashes, HMAC-based
|
||||
key derivation (HKDF), password-based key derivation (PBKDF2),
|
||||
and reasoning about elliptic curves.
|
||||
authenticated encryption, and reasoning about elliptic curves.
|
||||
|
||||
To read contents of external files, use `phrase_from_file/2` from
|
||||
[`library(pio)`](src/prolog/lib/pio.pl) to apply a DCG to
|
||||
|
||||
@@ -289,7 +289,9 @@ pub enum SystemClauseType {
|
||||
CryptoRandomByte,
|
||||
CryptoDataHash,
|
||||
CryptoDataHKDF,
|
||||
CryptoPasswordHash
|
||||
CryptoPasswordHash,
|
||||
CryptoDataEncrypt,
|
||||
CryptoDataDecrypt
|
||||
}
|
||||
|
||||
impl SystemClauseType {
|
||||
@@ -476,6 +478,8 @@ impl SystemClauseType {
|
||||
&SystemClauseType::CryptoDataHash => clause_name!("$crypto_data_hash"),
|
||||
&SystemClauseType::CryptoDataHKDF => clause_name!("$crypto_data_hkdf"),
|
||||
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
|
||||
&SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
|
||||
&SystemClauseType::CryptoDataDecrypt => clause_name!("$crypto_data_decrypt"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,6 +646,8 @@ impl SystemClauseType {
|
||||
("$crypto_data_hash", 3) => Some(SystemClauseType::CryptoDataHash),
|
||||
("$crypto_data_hkdf", 6) => Some(SystemClauseType::CryptoDataHKDF),
|
||||
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
||||
("$crypto_data_encrypt", 5) => Some(SystemClauseType::CryptoDataEncrypt),
|
||||
("$crypto_data_decrypt", 5) => Some(SystemClauseType::CryptoDataDecrypt),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,17 +12,20 @@
|
||||
using strings leaves little trace of what was processed in the system,
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
:- module(crypto, [hex_bytes/2, % ?Hex, ?Bytes
|
||||
crypto_n_random_bytes/2, % +N, -Bytes
|
||||
crypto_data_hash/3, % +Data, -Hash, +Options
|
||||
crypto_data_hkdf/4, % +Data, +Length, -Bytes, +Options
|
||||
crypto_name_curve/2, % +Name, -Curve
|
||||
crypto_curve_order/2, % +Curve, -Order
|
||||
crypto_curve_generator/2, % +Curve, -Generator
|
||||
crypto_curve_scalar_mult/4, % +Curve, +Scalar, +Point, -Result
|
||||
crypto_password_hash/2, % +Password, ?Hash
|
||||
crypto_password_hash/3 % +Password, -Hash, +Options
|
||||
]).
|
||||
:- module(crypto,
|
||||
[hex_bytes/2, % ?Hex, ?Bytes
|
||||
crypto_n_random_bytes/2, % +N, -Bytes
|
||||
crypto_data_hash/3, % +Data, -Hash, +Options
|
||||
crypto_data_hkdf/4, % +Data, +Length, -Bytes, +Options
|
||||
crypto_password_hash/2, % +Password, ?Hash
|
||||
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
|
||||
crypto_name_curve/2, % +Name, -Curve
|
||||
crypto_curve_order/2, % +Curve, -Order
|
||||
crypto_curve_generator/2, % +Curve, -Generator
|
||||
crypto_curve_scalar_mult/4 % +Curve, +Scalar, +Point, -Result
|
||||
]).
|
||||
|
||||
:- use_module(library(error)).
|
||||
:- use_module(library(lists)).
|
||||
@@ -152,16 +155,17 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
|
||||
characters, and Hash is the computed hash as a list of hexadecimal
|
||||
characters.
|
||||
|
||||
The single supported option is:
|
||||
Options is a list of:
|
||||
|
||||
algorithm(A)
|
||||
|
||||
where A is one of ripemd160, sha256, sha384, sha512, sha512_256,
|
||||
or a variable.
|
||||
|
||||
If A is a variable, then it is unified with the default algorithm,
|
||||
which is an algorithm that is considered cryptographically secure
|
||||
at the time of this writing.
|
||||
- algorithm(+A)
|
||||
where A is one of ripemd160, sha256, sha384, sha512,
|
||||
sha512_256, or a variable. If A is a variable, then it is
|
||||
unified with the default algorithm, which is an algorithm that
|
||||
is considered cryptographically secure at the time of this
|
||||
writing.
|
||||
- encoding(+Encoding)
|
||||
The default encoding is utf8. The alternative is octet,
|
||||
to treat the input as a list of raw bytes.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -179,8 +183,9 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
crypto_data_hash(Data0, Hash, Options0) :-
|
||||
chars_bytes_(Data0, Data, crypto_data_hash/3),
|
||||
must_be(list, Options0),
|
||||
option(encoding(Encoding), Options0, utf8),
|
||||
encoding_bytes(Encoding, Data0, Data),
|
||||
functor_hash_options(algorithm, A, Options0, _),
|
||||
( hash_algorithm(A) -> true
|
||||
; domain_error(hash_algorithm, A, crypto_data_hash/3)
|
||||
@@ -232,6 +237,9 @@ hash_algorithm(sha512_256).
|
||||
- salt(+List)
|
||||
Optionally, a list of bytes that are used as salt. The
|
||||
default is all zeroes.
|
||||
- encoding(+Encoding)
|
||||
The default encoding is utf8. The alternative is octet,
|
||||
to treat the input as a list of raw bytes.
|
||||
|
||||
The `info/1` option can be used to generate multiple keys from a
|
||||
single master key, using for example values such as "key" and
|
||||
@@ -242,7 +250,8 @@ hash_algorithm(sha512_256).
|
||||
|
||||
crypto_data_hkdf(Data0, L, Bytes, Options0) :-
|
||||
functor_hash_options(algorithm, Algorithm, Options0, Options),
|
||||
chars_bytes_(Data0, Data, crypto_data_hkdf/4),
|
||||
option(encoding(Encoding), Options, utf8),
|
||||
encoding_bytes(Encoding, Data0, Data),
|
||||
option(salt(SaltBytes), Options, []),
|
||||
must_be_bytes(SaltBytes, crypto_data_hkdf/4),
|
||||
option(info(Info0), Options, []),
|
||||
@@ -336,7 +345,7 @@ dollar_segments(Ls, Segments) :-
|
||||
|
||||
- algorithm(+Algorithm)
|
||||
The algorithm to use. Currently, the only available algorithm
|
||||
is =|pbkdf2-sha512|=, which is therefore also the default.
|
||||
is 'pbkdf2-sha512', which is therefore also the default.
|
||||
- cost(+C)
|
||||
C is an integer, denoting the binary logarithm of the number
|
||||
of _iterations_ used for the derivation of the hash. This
|
||||
@@ -435,6 +444,165 @@ bytes_base64_([A,B,C|Ls]) --> [W,X,Y,Z],
|
||||
bytes_base64_(Ls).
|
||||
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
crypto_data_encrypt(+PlainText,
|
||||
+Algorithm,
|
||||
+Key,
|
||||
+IV,
|
||||
-CipherText,
|
||||
+Options).
|
||||
|
||||
Encrypt the given PlainText, using the symmetric algorithm
|
||||
Algorithm, key Key, and initialization vector (or nonce) IV, to
|
||||
give CipherText.
|
||||
|
||||
PlainText must be a list of codes or characters, Key and IV must be
|
||||
lists of bytes, and CipherText is created as a list of characters.
|
||||
|
||||
Keys and IVs 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. This input is often a shared
|
||||
secret, such as a negotiated point on an elliptic curve, or the hash
|
||||
that was computed from a password via crypto_password_hash/3 with a
|
||||
freshly generated and specified _salt_.
|
||||
|
||||
Reusing the same combination of Key and IV typically leaks at least
|
||||
_some_ information about the plaintext. For example, identical
|
||||
plaintexts will then correspond to identical ciphertexts. For some
|
||||
algorithms, reusing an IV with the same Key has disastrous results
|
||||
and can cause the loss of all properties that are otherwise
|
||||
guaranteed. Especially in such cases, an IV is also called a
|
||||
_nonce_ (number used once).
|
||||
|
||||
It is safe to store and transfer the used initialization vector (or
|
||||
nonce) in plain text, but the key _must be kept secret_.
|
||||
|
||||
Currently, the only supported algorithm is 'chacha20-poly1305', a
|
||||
powerful and efficient _authenticated_ encryption scheme, providing
|
||||
secrecy and at the same time reliable protection against undetected
|
||||
_modifications_ of the encrypted data. This is a very good choice
|
||||
for virtually all use cases. It is a stream cipher and can encrypt
|
||||
data of any length up to 256 GB. Further, the encrypted data has
|
||||
exactly the same length as the original, and no padding is used.
|
||||
|
||||
Options:
|
||||
|
||||
- encoding(+Encoding)
|
||||
Encoding to use for PlainText. Default is utf8. The alternative
|
||||
is octet to treat PlainText as raw bytes.
|
||||
|
||||
- tag(-List)
|
||||
For authenticated encryption schemes, List is unified with a
|
||||
list of _bytes_ holding the tag. This tag must be provided for
|
||||
decryption.
|
||||
|
||||
Here is an example encryption and decryption, using the ChaCha20
|
||||
stream cipher with the Poly1305 authenticator. This cipher uses a
|
||||
256-bit key and a 96-bit nonce, i.e., 32 and 12 _bytes_,
|
||||
respectively:
|
||||
|
||||
?- Algorithm = 'chacha20-poly1305',
|
||||
crypto_n_random_bytes(32, Key),
|
||||
crypto_n_random_bytes(12, IV),
|
||||
crypto_data_encrypt("this text is to be encrypted", Algorithm,
|
||||
Key, IV, CipherText, [tag(Tag)]),
|
||||
crypto_data_decrypt(CipherText, Algorithm,
|
||||
Key, IV, RecoveredText, [tag(Tag)]).
|
||||
|
||||
Yielding:
|
||||
|
||||
Algorithm = 'chacha20-poly1305',
|
||||
Key = [113,247,153,134,177,220,13,193,50,150|...],
|
||||
IV = [135,20,149,153,63,35,68,114,247,171|...],
|
||||
CipherText = "\x94\0Ej\x94\®Â\x95\óÑÆXÃn¾ð©b\x1c\ ...",
|
||||
RecoveredText = "this text is to be ...",
|
||||
Tag = [152,117,152,17,162,75,150,206,144,40|...]
|
||||
|
||||
In this example, we use crypto_n_random_bytes/2 to generate a key
|
||||
and nonce from cryptographically secure random numbers. For
|
||||
repeated applications, you must ensure that a nonce is only used
|
||||
_once_ together with the same key. Note that for _authenticated_
|
||||
encryption schemes, the _tag_ that was computed during encryption
|
||||
is necessary for decryption. It is safe to store and transfer the
|
||||
tag in plain text.
|
||||
|
||||
See also crypto_data_decrypt/6, and hex_bytes/2 for conversion
|
||||
between bytes and hex encoding.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
|
||||
option(encoding(Encoding), Options, utf8),
|
||||
encoding_bytes(Encoding, PlainText0, PlainText),
|
||||
option(tag(Tag), Options, _),
|
||||
( nonvar(Tag) ->
|
||||
must_be_bytes(Tag, crypto_data_encrypt/6)
|
||||
; true
|
||||
),
|
||||
must_be_bytes(Key, crypto_data_encrypt/6),
|
||||
must_be_bytes(IV, crypto_data_encrypt/6),
|
||||
must_be(atom, Algorithm),
|
||||
( Algorithm = 'chacha20-poly1305' -> true
|
||||
; domain_error('chacha20-poly1305', Algorithm, crypto_data_encrypt/6)
|
||||
),
|
||||
'$crypto_data_encrypt'(PlainText, Key, IV, Tag, CipherText).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
crypto_data_decrypt(+CipherText,
|
||||
+Algorithm,
|
||||
+Key,
|
||||
+IV,
|
||||
-PlainText,
|
||||
+Options).
|
||||
|
||||
Decrypt the given CipherText, using the symmetric algorithm
|
||||
Algorithm, key Key, and initialization vector IV, to give
|
||||
PlainText. CipherText must be a list of bytes or characters, and
|
||||
Key and IV must be lists of bytes. PlainText is created as a list
|
||||
of characters.
|
||||
|
||||
Currently, the only supported algorithm is 'chacha20-poly1305',
|
||||
a very secure, fast and versatile authenticated encryption method.
|
||||
|
||||
Options is a list of:
|
||||
|
||||
- encoding(+Encoding)
|
||||
Encoding to use for PlainText. The default is utf8. The
|
||||
alternative is octet, which is used if the data are raw bytes.
|
||||
|
||||
- tag(+Tag)
|
||||
For authenticated encryption schemes, the tag must be specified as
|
||||
a list of bytes exactly as they were generated upon encryption.
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
|
||||
option(tag(Tag), Options, []),
|
||||
must_be_bytes(Tag, crypto_data_decrypt/6),
|
||||
must_be_bytes(Key, crypto_data_decrypt/6),
|
||||
must_be_bytes(IV, crypto_data_decrypt/6),
|
||||
must_be(atom, Algorithm),
|
||||
option(encoding(Encoding), Options, utf8),
|
||||
must_be(list, CipherText0),
|
||||
encoding_bytes(octet, CipherText0, CipherText1),
|
||||
append(CipherText1, Tag, CipherText),
|
||||
( Algorithm = 'chacha20-poly1305' -> true
|
||||
; domain_error('chacha20-poly1305', Algorithm, crypto_data_decrypt/6)
|
||||
),
|
||||
'$crypto_data_decrypt'(CipherText, Key, IV, Encoding, PlainText).
|
||||
|
||||
encoding_bytes(octet, Bs0, Bs) :-
|
||||
( maplist(integer, Bs0) ->
|
||||
Bs0 = Bs
|
||||
; maplist(char_code, Bs0, Bs)
|
||||
),
|
||||
must_be_bytes(Bs, crypto_encoding).
|
||||
encoding_bytes(utf8, Cs, Bs) :-
|
||||
( maplist(atom, Cs) ->
|
||||
chars_bytes_(Cs, Bs, crypto_encoding)
|
||||
; domain_error(encryption_encoding, Cs, crypto)
|
||||
).
|
||||
|
||||
char_code(Char, Code) :- atom_codes(Char, [Code]).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
Modular multiplicative inverse.
|
||||
|
||||
|
||||
@@ -275,8 +275,7 @@ cells(Fs0, Args, Tab, Es) -->
|
||||
cells(Fs, Args, Tab, [chars(Fs1)|Es]).
|
||||
|
||||
n_newlines(0) --> !.
|
||||
n_newlines(1) --> !, [newline].
|
||||
n_newlines(N0) --> { N0 > 1, N is N0 - 1 }, [newline], n_newlines(N).
|
||||
n_newlines(N0) --> { N0 > 0, N is N0 - 1 }, [newline], n_newlines(N).
|
||||
|
||||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
?- phrase(upto_what(Cs, ~), "abc~test", Rest).
|
||||
@@ -545,7 +544,7 @@ listing(PI) :-
|
||||
; type_error(predicate_indicator, PI, listing/1)
|
||||
),
|
||||
functor(Head, Name, Arity),
|
||||
\+ \+ clause(Head, Body), % only true if there is at least one clause
|
||||
\+ \+ clause(Head, _), % only true if there is at least one clause
|
||||
( clause(Head, Body),
|
||||
( Body == true ->
|
||||
portray_clause(Head)
|
||||
|
||||
@@ -40,7 +40,7 @@ use crate::crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
|
||||
use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode};
|
||||
|
||||
use ring::rand::{SecureRandom, SystemRandom};
|
||||
use ring::{digest,hkdf,pbkdf2};
|
||||
use ring::{digest,hkdf,pbkdf2,aead,error};
|
||||
use ripemd160::{Ripemd160, Digest};
|
||||
|
||||
pub fn get_key() -> KeyEvent {
|
||||
@@ -5326,6 +5326,85 @@ impl MachineState {
|
||||
|
||||
self.unify(self[temp_v!(4)], ints_list);
|
||||
}
|
||||
&SystemClauseType::CryptoDataEncrypt => {
|
||||
let stub1 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 6);
|
||||
let data = self.integers_to_bytevec(temp_v!(1), stub1);
|
||||
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 6);
|
||||
let key = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||
let stub3 = MachineError::functor_stub(clause_name!("crypto_data_encrypt"), 6);
|
||||
let iv = self.integers_to_bytevec(temp_v!(3), stub3);
|
||||
|
||||
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
|
||||
let nonce_sequence = OneNonceSequence::new(aead::Nonce::try_assume_unique_for_key(&iv).unwrap());
|
||||
let mut key: aead::SealingKey<OneNonceSequence> = aead::BoundKey::new(unbound_key, nonce_sequence);
|
||||
|
||||
let mut in_out = data.clone();
|
||||
let tag =
|
||||
match key.seal_in_place_separate_tag(aead::Aad::empty(), &mut in_out) {
|
||||
Ok(d) => { d }
|
||||
_ => { self.fail = true; return Ok(()); }
|
||||
};
|
||||
|
||||
let tag_list =
|
||||
Addr::HeapCell(self.heap.to_list(tag.as_ref().iter().map(|b| HeapCellValue::Integer(Rc::new(Integer::from(*b))))));
|
||||
|
||||
let complete_string = {
|
||||
let buffer = String::from_iter(in_out.iter().map(|b| *b as char));
|
||||
self.heap.put_complete_string(&buffer)
|
||||
};
|
||||
|
||||
self.unify(self[temp_v!(4)], tag_list);
|
||||
self.unify(self[temp_v!(5)], complete_string);
|
||||
}
|
||||
&SystemClauseType::CryptoDataDecrypt => {
|
||||
let stub1 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 6);
|
||||
let data = self.integers_to_bytevec(temp_v!(1), stub1);
|
||||
let stub2 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 6);
|
||||
let key = self.integers_to_bytevec(temp_v!(2), stub2);
|
||||
let stub3 = MachineError::functor_stub(clause_name!("crypto_data_decrypt"), 6);
|
||||
let iv = self.integers_to_bytevec(temp_v!(3), stub3);
|
||||
|
||||
let encoding = match self.store(self.deref(self[temp_v!(4)])) {
|
||||
Addr::Con(h) if self.heap.atom_at(h) => {
|
||||
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
|
||||
atom.as_str()
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
};
|
||||
|
||||
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap();
|
||||
let nonce_sequence = OneNonceSequence::new(aead::Nonce::try_assume_unique_for_key(&iv).unwrap());
|
||||
let mut key: aead::OpeningKey<OneNonceSequence> = aead::BoundKey::new(unbound_key, nonce_sequence);
|
||||
|
||||
let mut in_out = data.clone();
|
||||
|
||||
let complete_string = {
|
||||
let decrypted_data =
|
||||
match key.open_in_place(aead::Aad::empty(), &mut in_out) {
|
||||
Ok(d) => { d }
|
||||
_ => { self.fail = true; return Ok(()); }
|
||||
};
|
||||
|
||||
let buffer = match encoding {
|
||||
"octet" => { String::from_iter(decrypted_data.iter().map(|b| *b as char)) }
|
||||
"utf8" => { match String::from_utf8(decrypted_data.to_vec()) {
|
||||
Ok(str) => { str }
|
||||
_ => { self.fail = true; return Ok(()); }
|
||||
}
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
};
|
||||
|
||||
self.heap.put_complete_string(&buffer)
|
||||
};
|
||||
|
||||
self.unify(self[temp_v!(5)], complete_string);
|
||||
}
|
||||
};
|
||||
|
||||
return_from_clause!(self.last_call, self)
|
||||
@@ -5350,3 +5429,17 @@ impl hkdf::KeyType for MyKey<usize> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
struct OneNonceSequence(Option<aead::Nonce>);
|
||||
|
||||
impl OneNonceSequence {
|
||||
fn new(nonce: aead::Nonce) -> Self {
|
||||
Self(Some(nonce))
|
||||
}
|
||||
}
|
||||
|
||||
impl aead::NonceSequence for OneNonceSequence {
|
||||
fn advance(&mut self) -> Result<aead::Nonce, error::Unspecified> {
|
||||
self.0.take().ok_or(error::Unspecified)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user