Merge pull request #552 from mthom/master

Scryer Dockerfile
This commit is contained in:
Mark Thom
2020-05-22 16:04:03 -03:00
committed by GitHub
18 changed files with 499 additions and 256 deletions

View File

@@ -1,6 +0,0 @@
target
Dockerfile
README.md
.git
.gitignore
.gitmodules

55
Cargo.lock generated
View File

@@ -51,6 +51,18 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blake2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94cb07b0da6a73955f8fb85d24c466778e70cda767a568229b104f0264089330"
dependencies = [
"byte-tools",
"crypto-mac",
"digest",
"opaque-debug",
]
[[package]] [[package]]
name = "blake2b_simd" name = "blake2b_simd"
version = "0.5.10" version = "0.5.10"
@@ -174,6 +186,16 @@ dependencies = [
"winapi 0.3.8", "winapi 0.3.8",
] ]
[[package]]
name = "crypto-mac"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
dependencies = [
"generic-array",
"subtle",
]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.8.1" version = "0.8.1"
@@ -323,6 +345,12 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "keccak"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
[[package]] [[package]]
name = "kernel32-sys" name = "kernel32-sys"
version = "0.2.2" version = "0.2.2"
@@ -606,9 +634,9 @@ dependencies = [
[[package]] [[package]]
name = "prolog_parser" name = "prolog_parser"
version = "0.8.58" version = "0.8.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e90d34a4268bf5256d4e55f8ec920220aa96dc7ee779441b32f97635cba72aa9" checksum = "029a4682cf40923b8eb05c4b943d1d6be73775e7bf80bcb0866b5ef29abb0802"
dependencies = [ dependencies = [
"lexical", "lexical",
"num-rug-adapter", "num-rug-adapter",
@@ -740,8 +768,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.122" version = "0.8.123"
dependencies = [ dependencies = [
"blake2",
"cpu-time", "cpu-time",
"crossterm", "crossterm",
"dirs", "dirs",
@@ -761,6 +790,7 @@ dependencies = [
"ripemd160", "ripemd160",
"rug", "rug",
"rustyline", "rustyline",
"sha3",
"unicode_reader", "unicode_reader",
] ]
@@ -779,6 +809,19 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "sha3"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd26bc0e7a2e3a7c959bc494caf58b72ee0c71d67704e9520f736ca7e4853ecf"
dependencies = [
"block-buffer",
"byte-tools",
"digest",
"keccak",
"opaque-debug",
]
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.1.13" version = "0.1.13"
@@ -833,6 +876,12 @@ version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3" checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
[[package]]
name = "subtle"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.18" version = "1.0.18"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.122" version = "0.8.123"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
build = "build.rs" build = "build.rs"
repository = "https://github.com/mthom/scryer-prolog" repository = "https://github.com/mthom/scryer-prolog"
@@ -29,10 +29,12 @@ libc = "0.2.62"
nix = "0.15.0" nix = "0.15.0"
num-rug-adapter = { optional = true, version = "0.1.3" } num-rug-adapter = { optional = true, version = "0.1.3" }
ordered-float = "0.5.0" ordered-float = "0.5.0"
prolog_parser = { version = "0.8.58", default-features = false } prolog_parser = { version = "0.8.59", default-features = false }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"
rug = { version = "1.4.0", optional = true } rug = { version = "1.4.0", optional = true }
rustyline = "6.0.0" rustyline = "6.0.0"
unicode_reader = "1.0.0" unicode_reader = "1.0.0"
ring = "0.16.13" ring = "0.16.13"
ripemd160 = "0.8.0" ripemd160 = "0.8.0"
sha3 = "0.8.2"
blake2 = "0.8.1"

View File

@@ -1,30 +0,0 @@
# Based on https://hub.docker.com/_/rust?tab=description and https://hub.docker.com/_/rust?tab=description
# The first container is for build purposes only.
FROM rust as builder
WORKDIR /usr/src/scryer-prolog
# Using a dummy build.rs and src/main.rs with your Cargo.toml lets Docker cache your Rust dependencies and not rebuild
# them every time.
COPY Cargo.toml .
COPY Cargo.lock .
RUN mkdir -p src
RUN echo "fn main() {}" > src/main.rs
RUN echo "fn main() {}" > build.rs
RUN cargo build --release
# We need to touch our real main.rs and build.rs files or else
# docker will use the cached ones.
COPY . .
RUN touch src/main.rs
RUN touch build.rs
RUN cargo build --release
RUN ls ./target/release
# Finally, copy the scryer-prolog executable to a slimmer container.
FROM debian:buster-slim
COPY --from=builder /usr/src/scryer-prolog/target/release/scryer-prolog /usr/local/bin/scryer-prolog
CMD ["scryer-prolog"]

View File

@@ -93,8 +93,6 @@ strings.
## Installing Scryer Prolog ## Installing Scryer Prolog
### Native Install (Unix Only)
First, install the latest stable version of First, install the latest stable version of
[Rust](https://www.rust-lang.org/en-US/install.html) using your [Rust](https://www.rust-lang.org/en-US/install.html) using your
preferred method. Scryer tends to use features from newer Rust preferred method. Scryer tends to use features from newer Rust
@@ -128,26 +126,6 @@ $> cargo run [--release]
The optional `--release` flag will perform various optimizations, The optional `--release` flag will perform various optimizations,
producing a faster executable. producing a faster executable.
### Docker Install (All Platforms)
To automatically download, install, and run Scryer Prolog via Docker,
simply run:
```
$> docker run -it mthom/scryer-prolog
```
To be able to load your program files, bind mount your programs folder
as a Docker volume:
```
$> docker run -v /home/user/prolog:/mnt -it mthom/scryer-prolog
?- consult('mnt/program.pl').
true.
```
[Docker](https://hub.docker.com/editions/community/docker-ce-desktop-windows)
is currently the only way to run scryer-prolog on Windows.
## Tutorial ## Tutorial
Prolog files are loaded by specifying them as arguments on the command Prolog files are loaded by specifying them as arguments on the command
@@ -375,7 +353,7 @@ The modules that ship with Scryer&nbsp;Prolog are also called
* [`format`](src/prolog/lib/format.pl) * [`format`](src/prolog/lib/format.pl)
The nonterminal `format_//2` is used to describe formatted output, The nonterminal `format_//2` is used to describe formatted output,
arranging arguments according to a given format&nbsp;string. arranging arguments according to a given format&nbsp;string.
The predicates `format/2`, `portray_clause/1` and `listing/1` The predicates `format/[2,3]`, `portray_clause/1` and `listing/1`
provide formatted *impure* output. provide formatted *impure* output.
* [`assoc`](src/prolog/lib/assoc.pl) * [`assoc`](src/prolog/lib/assoc.pl)
providing `empty_assoc/1`, `get_assoc/3`, `put_assoc/4` etc. providing `empty_assoc/1`, `get_assoc/3`, `put_assoc/4` etc.
@@ -402,6 +380,7 @@ The modules that ship with Scryer&nbsp;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

View File

@@ -474,7 +474,12 @@ impl Neg for Number {
fn neg(self) -> Self::Output { fn neg(self) -> Self::Output {
match self { match self {
Number::Fixnum(n) => Number::Fixnum(-n), Number::Fixnum(n) =>
if let Some(n) = n.checked_neg() {
Number::Fixnum(n)
} else {
Number::from(-Integer::from(n))
}
Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))), Number::Integer(n) => Number::Integer(Rc::new(-Integer::from(&*n))),
Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)), Number::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))), Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))),

View File

@@ -229,6 +229,7 @@ pub enum SystemClauseType {
PeekCode, PeekCode,
PointsToContinuationResetMarker, PointsToContinuationResetMarker,
PutByte, PutByte,
PutBytes,
PutChar, PutChar,
PutCode, PutCode,
REPL(REPLCodePtr), REPL(REPLCodePtr),
@@ -291,7 +292,11 @@ pub enum SystemClauseType {
CryptoDataHKDF, CryptoDataHKDF,
CryptoPasswordHash, CryptoPasswordHash,
CryptoDataEncrypt, CryptoDataEncrypt,
CryptoDataDecrypt CryptoDataDecrypt,
Ed25519Sign,
Ed25519Verify,
Ed25519NewKeyPair,
Ed25519KeyPairPublicKey
} }
impl SystemClauseType { impl SystemClauseType {
@@ -411,6 +416,9 @@ impl SystemClauseType {
&SystemClauseType::PutByte => { &SystemClauseType::PutByte => {
clause_name!("$put_byte") clause_name!("$put_byte")
} }
&SystemClauseType::PutBytes => {
clause_name!("$put_bytes")
}
&SystemClauseType::PutChar => { &SystemClauseType::PutChar => {
clause_name!("$put_char") clause_name!("$put_char")
} }
@@ -480,6 +488,10 @@ 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"),
&SystemClauseType::Ed25519NewKeyPair => clause_name!("$ed25519_new_keypair"),
&SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key")
} }
} }
@@ -533,7 +545,7 @@ impl SystemClauseType {
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
("$file_to_chars", 2) => Some(SystemClauseType::FileToChars), ("$file_to_chars", 3) => Some(SystemClauseType::FileToChars),
("$get_byte", 2) => Some(SystemClauseType::GetByte), ("$get_byte", 2) => Some(SystemClauseType::GetByte),
("$get_char", 2) => Some(SystemClauseType::GetChar), ("$get_char", 2) => Some(SystemClauseType::GetChar),
("$get_code", 2) => Some(SystemClauseType::GetCode), ("$get_code", 2) => Some(SystemClauseType::GetCode),
@@ -544,6 +556,9 @@ impl SystemClauseType {
("$put_byte", 2) => { ("$put_byte", 2) => {
Some(SystemClauseType::PutByte) Some(SystemClauseType::PutByte)
} }
("$put_bytes", 2) => {
Some(SystemClauseType::PutBytes)
}
("$put_char", 2) => { ("$put_char", 2) => {
Some(SystemClauseType::PutChar) Some(SystemClauseType::PutChar)
} }
@@ -648,6 +663,10 @@ 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),
("$ed25519_new_keypair", 1) => Some(SystemClauseType::Ed25519NewKeyPair),
("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
_ => None, _ => None,
} }
} }

View File

@@ -92,6 +92,10 @@ fn is_partial_string<'a>(
Term::Constant(_, Constant::EmptyList) => { Term::Constant(_, Constant::EmptyList) => {
return Some((string, None)); return Some((string, None));
} }
Term::Constant(_, Constant::String(tail)) => {
string += &tail;
return Some((string, None));
}
_ => { _ => {
return None; return None;
} }

View File

@@ -9,22 +9,30 @@
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.
For predicates that accept an encoding/1 option to specify the encoding
of the input data, if encoding(octet) is used, then the input can also
be specified as a list of bytes, i.e., integers between 0 and 255.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(crypto, :- module(crypto,
[hex_bytes/2, % ?Hex, ?Bytes [hex_bytes/2, % ?Hex, ?Bytes
crypto_n_random_bytes/2, % +N, -Bytes crypto_n_random_bytes/2, % +N, -Bytes
crypto_data_hash/3, % +Data, -Hash, +Options crypto_data_hash/3, % +Data, -Hash, +Options
crypto_data_hkdf/4, % +Data, +Length, -Bytes, +Options crypto_data_hkdf/4, % +Data, +Length, -Bytes, +Options
crypto_password_hash/2, % +Password, ?Hash crypto_password_hash/2, % +Password, ?Hash
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
crypto_name_curve/2, % +Name, -Curve ed25519_new_keypair/1, % -KeyPair
crypto_curve_order/2, % +Curve, -Order ed25519_keypair_public_key/2, % +KeyPair, +PublicKey
crypto_curve_generator/2, % +Curve, -Generator ed25519_sign/4, % +KeyPair, +Data, -Signature, +Options
crypto_curve_scalar_mult/4 % +Curve, +Scalar, +Point, -Result ed25519_verify/4, % +PublicKey, +Data, +Signature, +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(error)).
@@ -151,18 +159,17 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
crypto_data_hash(+Data, -Hash, +Options) crypto_data_hash(+Data, -Hash, +Options)
Where Data is a list of bytes (integers between 0 and 255) or Where Data is a list of characters, and Hash is the computed hash
characters, and Hash is the computed hash as a list of hexadecimal as a list of hexadecimal characters.
characters.
Options is a list of: Options is a list of:
- algorithm(+A) - algorithm(+A)
where A is one of ripemd160, sha256, sha384, sha512, where A is one of ripemd160, sha256, sha384, sha512, sha512_256,
sha512_256, or a variable. If A is a variable, then it is sha3_224, sha3_256, sha3_384, sha3_512, blake2s256, blake2b512,
unified with the default algorithm, which is an algorithm that or a variable. If A is a variable, then it is unified with the
is considered cryptographically secure at the time of this default algorithm, which is an algorithm that is considered
writing. cryptographically secure at the time of this writing.
- encoding(+Encoding) - encoding(+Encoding)
The default encoding is utf8. The alternative is octet, The default encoding is utf8. The alternative is octet,
to treat the input as a list of raw bytes. to treat the input as a list of raw bytes.
@@ -184,8 +191,7 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
crypto_data_hash(Data0, Hash, Options0) :- crypto_data_hash(Data0, Hash, Options0) :-
must_be(list, Options0), must_be(list, Options0),
option(encoding(Encoding), Options0, utf8), options_data_bytes(Options0, Data0, Data),
encoding_bytes(Encoding, Data0, Data),
functor_hash_options(algorithm, A, Options0, _), functor_hash_options(algorithm, A, Options0, _),
( hash_algorithm(A) -> true ( hash_algorithm(A) -> true
; domain_error(hash_algorithm, A, crypto_data_hash/3) ; domain_error(hash_algorithm, A, crypto_data_hash/3)
@@ -193,6 +199,10 @@ crypto_data_hash(Data0, Hash, Options0) :-
'$crypto_data_hash'(Data, HashBytes, A), '$crypto_data_hash'(Data, HashBytes, A),
hex_bytes(Hash, HashBytes). hex_bytes(Hash, HashBytes).
options_data_bytes(Options, Data, Bytes) :-
option(encoding(Encoding), Options, utf8),
must_be(atom, Encoding),
encoding_bytes(Encoding, Data, Bytes).
default_hash(sha256). default_hash(sha256).
@@ -212,13 +222,19 @@ hash_algorithm(sha256).
hash_algorithm(sha512). hash_algorithm(sha512).
hash_algorithm(sha384). hash_algorithm(sha384).
hash_algorithm(sha512_256). hash_algorithm(sha512_256).
hash_algorithm(sha3_224).
hash_algorithm(sha3_256).
hash_algorithm(sha3_384).
hash_algorithm(sha3_512).
hash_algorithm(blake2s256).
hash_algorithm(blake2b512).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
crypto_data_hkdf(+Data, +Length, -Bytes, +Options) is det. crypto_data_hkdf(+Data, +Length, -Bytes, +Options) is det.
Concentrate possibly dispersed entropy of Data and then expand it Concentrate possibly dispersed entropy of Data and then expand it
to the desired length. Data is a list of bytes or characters. to the desired length. Data is a list of characters.
Bytes is unified with a list of bytes of length Length, and is Bytes is unified with a list of bytes of length Length, and is
suitable as input keying material and initialization vectors to suitable as input keying material and initialization vectors to
@@ -227,13 +243,12 @@ hash_algorithm(sha512_256).
Admissible options are: Admissible options are:
- algorithm(+Algorithm) - algorithm(+Algorithm)
A hashing algorithm as specified to crypto_data_hash/3. The One of sha256, sha384 or sha512. If you specify a variable,
default is a cryptographically secure algorithm. If you then it is unified with the algorithm that was used, which is a
specify a variable, then it is unified with the algorithm cryptographically secure algorithm by default.
that was used, which is a cryptographically secure algorithm.
- info(+Info) - info(+Info)
Optional context and application specific information, Optional context and application specific information,
specified as a list of bytes or characters. The default is []. specified as a list of characters. The default is [].
- salt(+List) - salt(+List)
Optionally, a list of bytes that are used as salt. The Optionally, a list of bytes that are used as salt. The
default is all zeroes. default is all zeroes.
@@ -250,15 +265,27 @@ hash_algorithm(sha512_256).
crypto_data_hkdf(Data0, L, Bytes, Options0) :- crypto_data_hkdf(Data0, L, Bytes, Options0) :-
functor_hash_options(algorithm, Algorithm, Options0, Options), functor_hash_options(algorithm, Algorithm, Options0, Options),
option(encoding(Encoding), Options, utf8), ( hkdf_algorithm(Algorithm) -> true
encoding_bytes(Encoding, Data0, Data), ; domain_error(hkdf_algorithm, Algorithm, crypto_data_hkdf/4)
),
must_be(integer, L),
L >= 0,
options_data_bytes(Options, Data0, Data),
option(salt(SaltBytes), Options, []), option(salt(SaltBytes), Options, []),
must_be_bytes(SaltBytes, crypto_data_hkdf/4), must_be_bytes(SaltBytes, crypto_data_hkdf/4),
option(info(Info0), Options, []), option(info(Info0), Options, []),
chars_bytes_(Info0, Info, crypto_data_hkdf/4), chars_bytes_(Info0, Info, crypto_data_hkdf/4),
'$crypto_data_hkdf'(Data, SaltBytes, Info, Algorithm, L, Bytes). '$crypto_data_hkdf'(Data, SaltBytes, Info, Algorithm, L, Bytes).
hkdf_algorithm(sha256).
hkdf_algorithm(sha384).
hkdf_algorithm(sha512).
option(What, Options, Default) :- option(What, Options, Default) :-
( member(V, Options), var(V) ->
instantiation_error(option/3)
; true
),
( member(What, Options) -> true ( member(What, Options) -> true
; What =.. [_,Default] ; What =.. [_,Default]
). ).
@@ -379,7 +406,7 @@ crypto_password_hash(Password0, Hash, Options) :-
Algorithm = 'pbkdf2-sha512', % current default and only option Algorithm = 'pbkdf2-sha512', % current default and only option
option(algorithm(Algorithm), Options, Algorithm), option(algorithm(Algorithm), Options, Algorithm),
( member(salt(SaltBytes), Options) -> ( member(salt(SaltBytes), Options) ->
true must_be_bytes(SaltBytes, crypto_password_hash/2)
; crypto_n_random_bytes(16, SaltBytes) ; crypto_n_random_bytes(16, SaltBytes)
), ),
'$crypto_password_hash'(Password, SaltBytes, Iterations, HashBytes), '$crypto_password_hash'(Password, SaltBytes, Iterations, HashBytes),
@@ -456,8 +483,8 @@ bytes_base64_([A,B,C|Ls]) --> [W,X,Y,Z],
Algorithm, key Key, and initialization vector (or nonce) IV, to Algorithm, key Key, and initialization vector (or nonce) IV, to
give CipherText. give CipherText.
PlainText must be a list of codes or characters, Key and IV must be PlainText must be a list of characters, Key and IV must be lists of
lists of bytes, and CipherText is created as a list of characters. bytes, and CipherText is created as a list of characters.
Keys and IVs can be chosen at random (using for example Keys and IVs can be chosen at random (using for example
crypto_n_random_bytes/2) or derived from input keying material (IKM) crypto_n_random_bytes/2) or derived from input keying material (IKM)
@@ -531,8 +558,7 @@ bytes_base64_([A,B,C|Ls]) --> [W,X,Y,Z],
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :- crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
option(encoding(Encoding), Options, utf8), options_data_bytes(Options, PlainText0, PlainText),
encoding_bytes(Encoding, PlainText0, PlainText),
option(tag(Tag), Options, _), option(tag(Tag), Options, _),
( nonvar(Tag) -> ( nonvar(Tag) ->
must_be_bytes(Tag, crypto_data_encrypt/6) must_be_bytes(Tag, crypto_data_encrypt/6)
@@ -556,9 +582,9 @@ crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
Decrypt the given CipherText, using the symmetric algorithm Decrypt the given CipherText, using the symmetric algorithm
Algorithm, key Key, and initialization vector IV, to give Algorithm, key Key, and initialization vector IV, to give
PlainText. CipherText must be a list of bytes or characters, and PlainText. CipherText must be a list of characters, and Key and IV
Key and IV must be lists of bytes. PlainText is created as a list must be lists of bytes. PlainText is created as a list of
of characters. characters.
Currently, the only supported algorithm is 'chacha20-poly1305', Currently, the only supported algorithm is 'chacha20-poly1305',
a very secure, fast and versatile authenticated encryption method. a very secure, fast and versatile authenticated encryption method.
@@ -581,6 +607,8 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
must_be_bytes(IV, crypto_data_decrypt/6), must_be_bytes(IV, crypto_data_decrypt/6),
must_be(atom, Algorithm), must_be(atom, Algorithm),
option(encoding(Encoding), Options, utf8), option(encoding(Encoding), Options, utf8),
must_be(atom, Encoding),
member(Encoding, [utf8,octet]),
must_be(list, CipherText0), must_be(list, CipherText0),
encoding_bytes(octet, CipherText0, CipherText1), encoding_bytes(octet, CipherText0, CipherText1),
append(CipherText1, Tag, CipherText), append(CipherText1, Tag, CipherText),
@@ -590,18 +618,70 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
'$crypto_data_decrypt'(CipherText, Key, IV, Encoding, PlainText). '$crypto_data_decrypt'(CipherText, Key, IV, Encoding, PlainText).
encoding_bytes(octet, Bs0, Bs) :- encoding_bytes(octet, Bs0, Bs) :-
must_be(list, Bs0),
( maplist(integer, Bs0) -> ( maplist(integer, Bs0) ->
Bs0 = Bs Bs0 = Bs
; maplist(char_code, Bs0, Bs) ; maplist(char_code, Bs0, Bs)
), ),
must_be_bytes(Bs, crypto_encoding). must_be_bytes(Bs, crypto_encoding).
encoding_bytes(utf8, Cs, Bs) :- encoding_bytes(utf8, Cs, Bs) :-
must_be(list, Cs),
( maplist(atom, Cs) -> ( maplist(atom, Cs) ->
chars_bytes_(Cs, Bs, crypto_encoding) chars_bytes_(Cs, Bs, crypto_encoding)
; domain_error(encryption_encoding, Cs, crypto) ; domain_error(encryption_encoding, Cs, crypto)
). ).
char_code(Char, Code) :- atom_codes(Char, [Code]). /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Digital signatures with Ed25519
===============================
- ed25519_new_keypair(-Pair)
Yields a new Ed25519 key pair Pair, a list of characters. 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_keypair_public_key(+Pair, -PublicKey)
PublicKey is the public key of the given key pair. The public key
can be used for signature verification, and can be shared freely.
The public key is represented as a list of characters.
- ed25519_sign(+Key, +Data, -Signature, +Options)
Key and Data must be lists of characters. Key is a key pair in
PKCS#8 v2 format as generated by ed25519_new_keypair/1. 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.
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 signing and verifying is:
- encoding(+Encoding)
The default encoding of Data is utf8. The alternative is octet,
which treats Data as a list of raw bytes.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ed25519_new_keypair(Pair) :-
'$ed25519_new_keypair'(Pair).
ed25519_keypair_public_key(Pair0, PublicKey) :-
encoding_bytes(octet, Pair0, Pair),
'$ed25519_keypair_public_key'(Pair, PublicKey).
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.

View File

@@ -49,6 +49,10 @@
The predicate format/2 is like format_//2, except that it outputs The predicate format/2 is like format_//2, except that it outputs
the text on the terminal instead of describing it declaratively. the text on the terminal instead of describing it declaratively.
format/3, used as format(Stream, FormatString, Arguments), outputs
the described string to the given Stream. If Stream is a binary
stream, then the code of each emitted character must be in 0..255.
If at all possible, format_//2 should be used, to stress pure parts If at all possible, format_//2 should be used, to stress pure parts
that enable easy testing etc. If necessary, you can emit the list Ls that enable easy testing etc. If necessary, you can emit the list Ls
with maplist(write, Ls). with maplist(write, Ls).
@@ -68,6 +72,7 @@
:- module(format, [format_//2, :- module(format, [format_//2,
format/2, format/2,
format/3,
portray_clause/1, portray_clause/1,
listing/1 listing/1
]). ]).
@@ -359,6 +364,26 @@ format(Fs, Args) :-
phrase(format_(Fs, Args), Cs), phrase(format_(Fs, Args), Cs),
maplist(write, Cs). maplist(write, Cs).
format(Stream, Fs, Args) :-
phrase(format_(Fs, Args), Cs),
( stream_property(Stream, type(binary)) ->
% maplist(char_code, Cs, Bytes) is currently a lot slower
% than first converting Cs to an atom, and then to codes.
% In the future, we can ideally avoid creating an atom here,
% since an atom leaves traces in the system.
atom_chars(A, Cs),
atom_codes(A, Bytes),
( member(NonByte, Bytes), NonByte > 255 ->
char_code(Char, NonByte),
throw(error(representation_error(Char), format/3))
; true
),
% For binary streams, we use a specialised internal predicate
% that uses only a single "write" operation for efficiency.
'$put_bytes'(Stream, Bytes)
; maplist(put_char(Stream), Cs)
).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
?- phrase(cells("hello", [], 0, []), Cs). ?- phrase(cells("hello", [], 0, []), Cs).

View File

@@ -1,12 +1,24 @@
:- module(pio, [phrase_from_file/2]). :- module(pio, [phrase_from_file/2,
phrase_from_file/3]).
:- use_module(library(dcgs)). :- use_module(library(dcgs)).
:- use_module(library(error)). :- use_module(library(error)).
:- use_module(library(lists), [member/2]).
phrase_from_file(NT, File) :- phrase_from_file(NT, File) :-
( var(File) -> instantiation_error(phrase_from_file/2) phrase_from_file(NT, File, []).
phrase_from_file(NT, File, Options) :-
( var(File) -> instantiation_error(phrase_from_file/3)
; (\+ atom(File) ; File = []) -> ; (\+ atom(File) ; File = []) ->
domain_error(source_sink, File, phrase_from_file/2) domain_error(source_sink, File, phrase_from_file/3)
; '$file_to_chars'(File, Chars), ; must_be(list, Options),
( member(Var, Options), var(Var) -> instantiation_error(phrase_from_file/3)
; member(type(Type), Options) ->
must_be(atom, Type),
member(Type, [text,binary])
; Type = text
),
'$file_to_chars'(File, Chars, Type),
phrase(NT, Chars) phrase(NT, Chars)
). ).

View File

@@ -398,7 +398,7 @@ impl MachineState {
match (n1, n2) { match (n1, n2) {
(Number::Fixnum(n1), Number::Fixnum(n2)) => { (Number::Fixnum(n1), Number::Fixnum(n2)) => {
if n1 != 1 && n2 < 0 { if n1 != 1 && n2 < -1 {
let n = Number::from(n1); let n = Number::from(n1);
let stub = MachineError::functor_stub(clause_name!("^"), 2); let stub = MachineError::functor_stub(clause_name!("^"), 2);
@@ -424,7 +424,7 @@ impl MachineState {
} }
} }
(Number::Fixnum(n1), Number::Integer(n2)) => { (Number::Fixnum(n1), Number::Integer(n2)) => {
if n1 != 1 && &*n2 < &0 { if n1 != 1 && &*n2 < &-1 {
let n = Number::from(n1); let n = Number::from(n1);
let stub = MachineError::functor_stub(clause_name!("^"), 2); let stub = MachineError::functor_stub(clause_name!("^"), 2);
@@ -442,7 +442,7 @@ impl MachineState {
} }
} }
(Number::Integer(n1), Number::Fixnum(n2)) => { (Number::Integer(n1), Number::Fixnum(n2)) => {
if &*n1 != &1 && n2 < 0 { if &*n1 != &1 && n2 < -1 {
let n = Number::Integer(n1); let n = Number::Integer(n1);
let stub = MachineError::functor_stub(clause_name!("^"), 2); let stub = MachineError::functor_stub(clause_name!("^"), 2);
@@ -460,7 +460,7 @@ impl MachineState {
} }
} }
(Number::Integer(n1), Number::Integer(n2)) => { (Number::Integer(n1), Number::Integer(n2)) => {
if &*n1 != &1 && &*n2 < &0 { if &*n1 != &1 && &*n2 < &-1 {
let n = Number::Integer(n1); let n = Number::Integer(n1);
let stub = MachineError::functor_stub(clause_name!("^"), 2); let stub = MachineError::functor_stub(clause_name!("^"), 2);

View File

@@ -348,7 +348,9 @@ fn compile_into_module(
); );
match compile_into_module_impl(wam, &mut compiler, module, src, indices) { match compile_into_module_impl(wam, &mut compiler, module, src, indices) {
Ok(()) => EvalSession::EntrySuccess, Ok(()) => {
EvalSession::EntrySuccess
}
Err(e) => { Err(e) => {
compiler.drop_expansions(&mut wam.code_repo); compiler.drop_expansions(&mut wam.code_repo);
EvalSession::from(e) EvalSession::from(e)

View File

@@ -189,6 +189,10 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
#[inline] #[inline]
pub(crate) pub(crate)
fn put_complete_string(&mut self, s: &str) -> Addr { fn put_complete_string(&mut self, s: &str) -> Addr {
if s.is_empty() {
return Addr::EmptyList;
}
let addr = self.allocate_pstr(s); let addr = self.allocate_pstr(s);
self.pop(); self.pop();
@@ -316,20 +320,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
pub(crate) pub(crate)
fn allocate_pstr(&mut self, src: &str) -> Addr { fn allocate_pstr(&mut self, src: &str) -> Addr {
self.write_pstr(src) self.write_pstr(src)
.unwrap_or_else(|| { .unwrap_or_else(|| Addr::EmptyList)
let h = self.h();
self.push(HeapCellValue::PartialString(
PartialString::empty(),
true,
));
self.push(HeapCellValue::Addr(
Addr::HeapCell(h + 1)
));
Addr::PStrLocation(h, 0)
})
} }
#[inline] #[inline]

View File

@@ -1492,9 +1492,13 @@ impl MachineState {
&QueryInstruction::PutPartialString(_, ref string, reg, has_tail) => { &QueryInstruction::PutPartialString(_, ref string, reg, has_tail) => {
let pstr_addr = let pstr_addr =
if has_tail { if has_tail {
let pstr_addr = self.heap.allocate_pstr(&string); if !string.is_empty() {
self.heap.pop(); // the tail will be added by the next instruction. let pstr_addr = self.heap.allocate_pstr(&string);
pstr_addr self.heap.pop(); // the tail will be added by the next instruction.
pstr_addr
} else {
Addr::EmptyList
}
} else { } else {
self.heap.put_complete_string(&string) self.heap.put_complete_string(&string)
}; };

View File

@@ -37,8 +37,8 @@ fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
let mut terminator_idx = 0; let mut terminator_idx = 0;
for c in iter { for c in iter {
if c == '\u{0}' { if c == '\u{0}' && terminator_idx != 0 {
break; return terminator_idx;
} }
terminator_idx += c.len_utf8(); terminator_idx += c.len_utf8();
@@ -98,37 +98,9 @@ impl PartialString {
} }
} }
#[inline]
pub(super)
fn empty() -> Self {
let mut pstr = PartialString {
buf: ptr::null(),
len: 0,
_marker: PhantomData,
};
unsafe {
let layout = alloc::Layout::from_size_align_unchecked(
'\u{0}'.len_utf8(),
mem::align_of::<u8>(),
);
pstr.buf = alloc::alloc(layout) as *const _;
pstr.len = '\u{0}'.len_utf8();
pstr.write_terminator_at(0);
}
pstr
}
unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> { unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
let terminator_idx = scan_for_terminator(src.chars()); let terminator_idx = scan_for_terminator(src.chars());
if terminator_idx == 0 {
return None;
}
let layout = alloc::Layout::from_size_align_unchecked( let layout = alloc::Layout::from_size_align_unchecked(
terminator_idx + '\u{0}'.len_utf8(), terminator_idx + '\u{0}'.len_utf8(),
mem::align_of::<u8>(), mem::align_of::<u8>(),
@@ -145,8 +117,8 @@ impl PartialString {
self.write_terminator_at(terminator_idx); self.write_terminator_at(terminator_idx);
Some(if terminator_idx != src.len() { Some(if terminator_idx != src.as_bytes().len() {
(self, &src[terminator_idx + '\u{0}'.len_utf8() ..]) (self, &src[terminator_idx ..])
} else { } else {
(self, "") (self, "")
}) })
@@ -211,9 +183,7 @@ impl PartialString {
#[inline] #[inline]
pub fn at_end(&self, end_n: usize) -> bool { pub fn at_end(&self, end_n: usize) -> bool {
unsafe { end_n + 1 == self.len
ptr::read((self.buf as usize + end_n) as *const u8) == 0u8
}
} }
#[inline] #[inline]

View File

@@ -688,9 +688,14 @@ impl MachineState {
return Err(self.open_past_eos_error(stream.clone(), caller, arity)); return Err(self.open_past_eos_error(stream.clone(), caller, arity));
} }
EOFAction::EOFCode => { EOFAction::EOFCode => {
let end_of_stream = self.heap.to_unifiable( let end_of_stream =
HeapCellValue::Atom(clause_name!("end_of_file"), None) if stream.options.stream_type == StreamType::Binary {
); Addr::Fixnum(-1)
} else {
self.heap.to_unifiable(
HeapCellValue::Atom(clause_name!("end_of_file"), None)
)
};
stream.set_past_end_of_stream(); stream.set_past_end_of_stream();
Ok(self.unify(result, end_of_stream)) Ok(self.unify(result, end_of_stream))

View File

@@ -40,8 +40,10 @@ 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,signature::{self,KeyPair}};
use ripemd160::{Ripemd160, Digest}; use ripemd160::{Ripemd160, Digest};
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
use blake2::{Blake2s, Blake2b};
pub fn get_key() -> KeyEvent { pub fn get_key() -> KeyEvent {
let key; let key;
@@ -1110,6 +1112,11 @@ impl MachineState {
let h = self.heap.h(); let h = self.heap.h();
if atom.as_str().is_empty() {
self.fail = true;
return Ok(());
}
let pstr = self.heap.allocate_pstr(atom.as_str()); let pstr = self.heap.allocate_pstr(atom.as_str());
let pstr_tail = self.heap[h + 1].as_addr(h + 1); let pstr_tail = self.heap[h + 1].as_addr(h + 1);
@@ -1154,10 +1161,22 @@ impl MachineState {
match pstr { match pstr {
Addr::PStrLocation(h, _) => { Addr::PStrLocation(h, _) => {
let tail = self.heap[h + 1].as_addr(h + 1); if let HeapCellValue::PartialString(_, true) = &self.heap[h] {
let target = self[temp_v!(2)]; let tail = self.heap[h + 1].as_addr(h + 1);
let target = self[temp_v!(2)];
self.unify(tail, target); self.unify(tail, target);
} else {
self.fail = true;
return Ok(());
}
}
Addr::Lis(h) => {
self.unify(Addr::HeapCell(h + 1), self[temp_v!(2)]);
}
Addr::EmptyList => {
self.fail = true;
return Ok(());
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -1888,29 +1907,51 @@ impl MachineState {
} }
}; };
let complete_string = {
let mut buffer = String::new();
match file.read_to_string(&mut buffer) {
Ok(_size) => {
self.heap.put_complete_string(&buffer)
}
Err(_e) => {
// This case if the data isn't UTF-8 valid.
let mut buffer = Vec::new();
let _ = match file.read_to_end(&mut buffer) {
Ok(size) => size,
Err(_e) => unreachable!()
};
let buffer = String::from_iter( let type_str = match self.store(self.deref(self[temp_v!(3)])) {
buffer.into_iter().map(|b| b as char) Addr::Con(h) if self.heap.atom_at(h) => {
); if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
atom.as_str()
self.heap.put_complete_string(&buffer) } else {
unreachable!()
} }
} }
_ => {
unreachable!()
}
}; };
let complete_string = {
let mut buffer = String::new();
match type_str {
"text" => { match file.read_to_string(&mut buffer) {
Ok(_size) => {
self.heap.put_complete_string(&buffer)
}
Err(_e) => {
// the data isn't valid UTF-8, so we fail.
self.fail = true;
return Ok(());
}
}
}
"binary" => { let mut buffer = Vec::new();
let _ = match file.read_to_end(&mut buffer) {
Ok(size) => size,
Err(_e) => unreachable!()
};
let buffer = String::from_iter(
buffer.into_iter().map(|b| b as char)
);
self.heap.put_complete_string(&buffer)
}
_ => { unreachable!() }
}
};
self.unify(complete_string, a2); self.unify(complete_string, a2);
} }
&SystemClauseType::PutCode => { &SystemClauseType::PutCode => {
@@ -2112,6 +2153,37 @@ impl MachineState {
} }
} }
} }
&SystemClauseType::PutBytes => {
let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "$put_bytes", 2)?;
let stub = MachineError::functor_stub(clause_name!("$put_bytes"), 2);
let bytes = self.integers_to_bytevec(temp_v!(2), stub);
match stream.write(&bytes) {
Ok(_) => {
return return_from_clause!(self.last_call, self);
}
_ => {
let stub = MachineError::functor_stub(
clause_name!("$put_bytes"),
2,
);
let addr = self.heap.to_unifiable(
HeapCellValue::Stream(stream.clone()),
);
return Err(self.error_form(
MachineError::existence_error(
self.heap.h(),
ExistenceError::Stream(addr),
),
stub,
));
}
}
}
&SystemClauseType::GetByte => { &SystemClauseType::GetByte => {
let mut stream = let mut stream =
self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?; self.get_stream_or_alias(self[temp_v!(1)], indices, "get_byte", 2)?;
@@ -2125,6 +2197,13 @@ impl MachineState {
)?; )?;
if stream.past_end_of_stream() { if stream.past_end_of_stream() {
self.eof_action(
self[temp_v!(2)],
&mut stream,
clause_name!("get_byte"),
2,
)?;
if EOFAction::Reset != stream.options.eof_action { if EOFAction::Reset != stream.options.eof_action {
return return_from_clause!(self.last_call, self); return return_from_clause!(self.last_call, self);
} else if self.fail { } else if self.fail {
@@ -2132,12 +2211,6 @@ impl MachineState {
} }
} }
if stream.at_end_of_stream() {
stream.set_past_end_of_stream();
self.unify(self[temp_v!(2)], Addr::Fixnum(-1));
return return_from_clause!(self.last_call, self);
}
let addr = let addr =
match self.store(self.deref(self[temp_v!(2)])) { match self.store(self.deref(self[temp_v!(2)])) {
addr if addr.is_ref() => { addr if addr.is_ref() => {
@@ -2197,18 +2270,9 @@ impl MachineState {
} }
} }
_ => { _ => {
self.eof_action( stream.set_past_end_of_stream();
self[temp_v!(2)], self.unify(self[temp_v!(2)], Addr::Fixnum(-1));
&mut stream, return return_from_clause!(self.last_call, self);
clause_name!("get_byte"),
2,
)?;
if EOFAction::Reset != stream.options.eof_action {
return return_from_clause!(self.last_call, self);
} else if self.fail {
return Ok(());
}
} }
} }
} }
@@ -5202,21 +5266,39 @@ impl MachineState {
}; };
let ints_list = let ints_list =
if algorithm_str == "ripemd160" { match algorithm_str {
let mut context = Ripemd160::new(); "sha3_224" => { let mut context = Sha3_224::new();
context.input(&bytes); context.input(&bytes);
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::Integer(Rc::new(Integer::from(*b)))))) Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
} else { "sha3_256" => { let mut context = Sha3_256::new();
let ints = digest::digest( context.input(&bytes);
match algorithm_str { Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
"sha256" => { &digest::SHA256 } "sha3_384" => { let mut context = Sha3_384::new();
"sha384" => { &digest::SHA384 } context.input(&bytes);
"sha512" => { &digest::SHA512 } Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
"sha512_256" => { &digest::SHA512_256 } "sha3_512" => { let mut context = Sha3_512::new();
_ => { unreachable!() } context.input(&bytes);
}, Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
&bytes); "blake2s256" => { let mut context = Blake2s::new();
Addr::HeapCell(self.heap.to_list(ints.as_ref().iter().map(|b| HeapCellValue::Integer(Rc::new(Integer::from(*b)))))) context.input(&bytes);
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
"blake2b512" => { let mut context = Blake2b::new();
context.input(&bytes);
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
"ripemd160" => { let mut context = Ripemd160::new();
context.input(&bytes);
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
_ => { let ints = digest::digest(
match algorithm_str {
"sha256" => { &digest::SHA256 }
"sha384" => { &digest::SHA384 }
"sha512" => { &digest::SHA512 }
"sha512_256" => { &digest::SHA512_256 }
_ => { unreachable!() }
},
&bytes);
Addr::HeapCell(self.heap.to_list(ints.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize)))))
}
}; };
self.unify(self[temp_v!(2)], ints_list); self.unify(self[temp_v!(2)], ints_list);
@@ -5248,11 +5330,12 @@ impl MachineState {
usize::try_from(n).unwrap() usize::try_from(n).unwrap()
} }
Ok(Number::Integer(n)) => { Ok(Number::Integer(n)) => {
n.to_usize().unwrap() match n.to_usize() {
} Some(u) => { u }
_ => { _ => { self.fail = true; return Ok(()); }
unreachable!() }
} }
_ => { unreachable!() }
}; };
let ints_list = let ints_list =
@@ -5261,14 +5344,17 @@ impl MachineState {
"sha256" => { hkdf::HKDF_SHA256 } "sha256" => { hkdf::HKDF_SHA256 }
"sha384" => { hkdf::HKDF_SHA384 } "sha384" => { hkdf::HKDF_SHA384 }
"sha512" => { hkdf::HKDF_SHA512 } "sha512" => { hkdf::HKDF_SHA512 }
_ => { unreachable!() } _ => { self.fail = true; return Ok(()); }
}; };
let salt = hkdf::Salt::new(digest_alg, &salt); let salt = hkdf::Salt::new(digest_alg, &salt);
let mut bytes : Vec<u8> = Vec::new(); let mut bytes : Vec<u8> = Vec::new();
bytes.resize(length, 0); bytes.resize(length, 0);
salt.extract(&data).expand(&[&info[..]], MyKey(length)).unwrap().fill(&mut bytes).unwrap(); match salt.extract(&data).expand(&[&info[..]], MyKey(length)) {
Ok(r) => { r.fill(&mut bytes).unwrap(); }
_ => { self.fail = true; return Ok(()); }
}
Addr::HeapCell(self.heap.to_list(bytes.iter().map(|b| HeapCellValue::Integer(Rc::new(Integer::from(*b)))))) Addr::HeapCell(self.heap.to_list(bytes.iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize)))))
}; };
self.unify(self[temp_v!(6)], ints_list); self.unify(self[temp_v!(6)], ints_list);
@@ -5285,7 +5371,10 @@ impl MachineState {
u64::try_from(n).unwrap() u64::try_from(n).unwrap()
} }
Ok(Number::Integer(n)) => { Ok(Number::Integer(n)) => {
n.to_u64().unwrap() match n.to_u64() {
Some(i) => { i }
None => { self.fail = true; return Ok(()); }
}
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -5298,7 +5387,7 @@ impl MachineState {
NonZeroU32::new(iterations as u32).unwrap(), &salt, NonZeroU32::new(iterations as u32).unwrap(), &salt,
&data, &mut bytes); &data, &mut bytes);
Addr::HeapCell(self.heap.to_list(bytes.iter().map(|b| HeapCellValue::Integer(Rc::new(Integer::from(*b)))))) Addr::HeapCell(self.heap.to_list(bytes.iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize)))))
}; };
self.unify(self[temp_v!(4)], ints_list); self.unify(self[temp_v!(4)], ints_list);
@@ -5312,18 +5401,18 @@ impl MachineState {
let iv = self.integers_to_bytevec(temp_v!(3), stub3); let iv = self.integers_to_bytevec(temp_v!(3), stub3);
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); 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 nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
let mut key: aead::SealingKey<OneNonceSequence> = aead::BoundKey::new(unbound_key, nonce_sequence); let key = aead::LessSafeKey::new(unbound_key);
let mut in_out = data.clone(); let mut in_out = data.clone();
let tag = let tag =
match key.seal_in_place_separate_tag(aead::Aad::empty(), &mut in_out) { match key.seal_in_place_separate_tag(nonce, aead::Aad::empty(), &mut in_out) {
Ok(d) => { d } Ok(d) => { d }
_ => { self.fail = true; return Ok(()); } _ => { self.fail = true; return Ok(()); }
}; };
let tag_list = let tag_list =
Addr::HeapCell(self.heap.to_list(tag.as_ref().iter().map(|b| HeapCellValue::Integer(Rc::new(Integer::from(*b)))))); Addr::HeapCell(self.heap.to_list(tag.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize)))));
let complete_string = { let complete_string = {
let buffer = String::from_iter(in_out.iter().map(|b| *b as char)); let buffer = String::from_iter(in_out.iter().map(|b| *b as char));
@@ -5355,14 +5444,14 @@ impl MachineState {
}; };
let unbound_key = aead::UnboundKey::new(&aead::CHACHA20_POLY1305, &key).unwrap(); 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 nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
let mut key: aead::OpeningKey<OneNonceSequence> = aead::BoundKey::new(unbound_key, nonce_sequence); let key = aead::LessSafeKey::new(unbound_key);
let mut in_out = data.clone(); let mut in_out = data.clone();
let complete_string = { let complete_string = {
let decrypted_data = let decrypted_data =
match key.open_in_place(aead::Aad::empty(), &mut in_out) { match key.open_in_place(nonce, aead::Aad::empty(), &mut in_out) {
Ok(d) => { d } Ok(d) => { d }
_ => { self.fail = true; return Ok(()); } _ => { self.fail = true; return Ok(()); }
}; };
@@ -5382,6 +5471,63 @@ impl MachineState {
self.unify(self[temp_v!(5)], complete_string); self.unify(self[temp_v!(5)], complete_string);
} }
&SystemClauseType::Ed25519NewKeyPair => {
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(rng()).unwrap();
let complete_string = {
let buffer = String::from_iter(pkcs8_bytes.as_ref().iter().map(|b| *b as char));
self.heap.put_complete_string(&buffer)
};
self.unify(self[temp_v!(1)], complete_string);
}
&SystemClauseType::Ed25519KeyPairPublicKey => {
let stub1 = MachineError::functor_stub(clause_name!("ed25519_keypair_public_key"), 2);
let bytes = self.integers_to_bytevec(temp_v!(1), stub1);
let key_pair = match signature::Ed25519KeyPair::from_pkcs8(&bytes) {
Ok(kp) => { kp }
_ => { self.fail = true; return Ok(()); }
};
let complete_string = {
let buffer = String::from_iter(key_pair.public_key().as_ref().iter().map(|b| *b as char));
self.heap.put_complete_string(&buffer)
};
self.unify(self[temp_v!(2)], 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(&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)
@@ -5406,17 +5552,3 @@ impl hkdf::KeyType for MyKey<usize> {
self.0 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)
}
}