@@ -1,6 +0,0 @@
|
||||
target
|
||||
Dockerfile
|
||||
README.md
|
||||
.git
|
||||
.gitignore
|
||||
.gitmodules
|
||||
55
Cargo.lock
generated
55
Cargo.lock
generated
@@ -51,6 +51,18 @@ version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.10"
|
||||
@@ -174,6 +186,16 @@ dependencies = [
|
||||
"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]]
|
||||
name = "digest"
|
||||
version = "0.8.1"
|
||||
@@ -323,6 +345,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "keccak"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
@@ -606,9 +634,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "prolog_parser"
|
||||
version = "0.8.58"
|
||||
version = "0.8.59"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e90d34a4268bf5256d4e55f8ec920220aa96dc7ee779441b32f97635cba72aa9"
|
||||
checksum = "029a4682cf40923b8eb05c4b943d1d6be73775e7bf80bcb0866b5ef29abb0802"
|
||||
dependencies = [
|
||||
"lexical",
|
||||
"num-rug-adapter",
|
||||
@@ -740,8 +768,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scryer-prolog"
|
||||
version = "0.8.122"
|
||||
version = "0.8.123"
|
||||
dependencies = [
|
||||
"blake2",
|
||||
"cpu-time",
|
||||
"crossterm",
|
||||
"dirs",
|
||||
@@ -761,6 +790,7 @@ dependencies = [
|
||||
"ripemd160",
|
||||
"rug",
|
||||
"rustyline",
|
||||
"sha3",
|
||||
"unicode_reader",
|
||||
]
|
||||
|
||||
@@ -779,6 +809,19 @@ version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "signal-hook"
|
||||
version = "0.1.13"
|
||||
@@ -833,6 +876,12 @@ version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f3eb36b47e512f8f1c9e3d10c2c1965bc992bd9cdb024fa581e2194501c83d3"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.18"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "scryer-prolog"
|
||||
version = "0.8.122"
|
||||
version = "0.8.123"
|
||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||
build = "build.rs"
|
||||
repository = "https://github.com/mthom/scryer-prolog"
|
||||
@@ -29,10 +29,12 @@ libc = "0.2.62"
|
||||
nix = "0.15.0"
|
||||
num-rug-adapter = { optional = true, version = "0.1.3" }
|
||||
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"
|
||||
rug = { version = "1.4.0", optional = true }
|
||||
rustyline = "6.0.0"
|
||||
unicode_reader = "1.0.0"
|
||||
ring = "0.16.13"
|
||||
ripemd160 = "0.8.0"
|
||||
sha3 = "0.8.2"
|
||||
blake2 = "0.8.1"
|
||||
|
||||
30
Dockerfile
30
Dockerfile
@@ -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"]
|
||||
25
README.md
25
README.md
@@ -93,8 +93,6 @@ strings.
|
||||
|
||||
## Installing Scryer Prolog
|
||||
|
||||
### Native Install (Unix Only)
|
||||
|
||||
First, install the latest stable version of
|
||||
[Rust](https://www.rust-lang.org/en-US/install.html) using your
|
||||
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,
|
||||
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
|
||||
|
||||
Prolog files are loaded by specifying them as arguments on the command
|
||||
@@ -375,7 +353,7 @@ The modules that ship with Scryer Prolog are also called
|
||||
* [`format`](src/prolog/lib/format.pl)
|
||||
The nonterminal `format_//2` is used to describe formatted output,
|
||||
arranging arguments according to a given format 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.
|
||||
* [`assoc`](src/prolog/lib/assoc.pl)
|
||||
providing `empty_assoc/1`, `get_assoc/3`, `put_assoc/4` etc.
|
||||
@@ -402,6 +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),
|
||||
public key signatures and signature verification with Ed25519,
|
||||
authenticated encryption, and reasoning about elliptic curves.
|
||||
|
||||
To read contents of external files, use `phrase_from_file/2` from
|
||||
|
||||
@@ -474,7 +474,12 @@ impl Neg for Number {
|
||||
|
||||
fn neg(self) -> Self::Output {
|
||||
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::Float(OrderedFloat(f)) => Number::Float(OrderedFloat(-f)),
|
||||
Number::Rational(r) => Number::Rational(Rc::new(-Rational::from(&*r))),
|
||||
|
||||
@@ -229,6 +229,7 @@ pub enum SystemClauseType {
|
||||
PeekCode,
|
||||
PointsToContinuationResetMarker,
|
||||
PutByte,
|
||||
PutBytes,
|
||||
PutChar,
|
||||
PutCode,
|
||||
REPL(REPLCodePtr),
|
||||
@@ -291,7 +292,11 @@ pub enum SystemClauseType {
|
||||
CryptoDataHKDF,
|
||||
CryptoPasswordHash,
|
||||
CryptoDataEncrypt,
|
||||
CryptoDataDecrypt
|
||||
CryptoDataDecrypt,
|
||||
Ed25519Sign,
|
||||
Ed25519Verify,
|
||||
Ed25519NewKeyPair,
|
||||
Ed25519KeyPairPublicKey
|
||||
}
|
||||
|
||||
impl SystemClauseType {
|
||||
@@ -411,6 +416,9 @@ impl SystemClauseType {
|
||||
&SystemClauseType::PutByte => {
|
||||
clause_name!("$put_byte")
|
||||
}
|
||||
&SystemClauseType::PutBytes => {
|
||||
clause_name!("$put_bytes")
|
||||
}
|
||||
&SystemClauseType::PutChar => {
|
||||
clause_name!("$put_char")
|
||||
}
|
||||
@@ -480,6 +488,10 @@ impl SystemClauseType {
|
||||
&SystemClauseType::CryptoPasswordHash => clause_name!("$crypto_password_hash"),
|
||||
&SystemClauseType::CryptoDataEncrypt => clause_name!("$crypto_data_encrypt"),
|
||||
&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),
|
||||
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
||||
("$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_char", 2) => Some(SystemClauseType::GetChar),
|
||||
("$get_code", 2) => Some(SystemClauseType::GetCode),
|
||||
@@ -544,6 +556,9 @@ impl SystemClauseType {
|
||||
("$put_byte", 2) => {
|
||||
Some(SystemClauseType::PutByte)
|
||||
}
|
||||
("$put_bytes", 2) => {
|
||||
Some(SystemClauseType::PutBytes)
|
||||
}
|
||||
("$put_char", 2) => {
|
||||
Some(SystemClauseType::PutChar)
|
||||
}
|
||||
@@ -648,6 +663,10 @@ impl SystemClauseType {
|
||||
("$crypto_password_hash", 4) => Some(SystemClauseType::CryptoPasswordHash),
|
||||
("$crypto_data_encrypt", 5) => Some(SystemClauseType::CryptoDataEncrypt),
|
||||
("$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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,10 @@ fn is_partial_string<'a>(
|
||||
Term::Constant(_, Constant::EmptyList) => {
|
||||
return Some((string, None));
|
||||
}
|
||||
Term::Constant(_, Constant::String(tail)) => {
|
||||
string += &tail;
|
||||
return Some((string, None));
|
||||
}
|
||||
_ => {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -9,22 +9,30 @@
|
||||
and strings have the advantage that the atom table remains unmodified.
|
||||
|
||||
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,
|
||||
[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
|
||||
[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
|
||||
ed25519_new_keypair/1, % -KeyPair
|
||||
ed25519_keypair_public_key/2, % +KeyPair, +PublicKey
|
||||
ed25519_sign/4, % +KeyPair, +Data, -Signature, +Options
|
||||
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)).
|
||||
@@ -151,18 +159,17 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
|
||||
|
||||
crypto_data_hash(+Data, -Hash, +Options)
|
||||
|
||||
Where Data is a list of bytes (integers between 0 and 255) or
|
||||
characters, and Hash is the computed hash as a list of hexadecimal
|
||||
characters.
|
||||
Where Data is a list of characters, and Hash is the computed hash
|
||||
as a list of hexadecimal characters.
|
||||
|
||||
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.
|
||||
where A is one of ripemd160, sha256, sha384, sha512, sha512_256,
|
||||
sha3_224, sha3_256, sha3_384, sha3_512, blake2s256, blake2b512,
|
||||
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.
|
||||
@@ -184,8 +191,7 @@ crypto_random_byte(B) :- '$crypto_random_byte'(B).
|
||||
|
||||
crypto_data_hash(Data0, Hash, Options0) :-
|
||||
must_be(list, Options0),
|
||||
option(encoding(Encoding), Options0, utf8),
|
||||
encoding_bytes(Encoding, Data0, Data),
|
||||
options_data_bytes(Options0, Data0, Data),
|
||||
functor_hash_options(algorithm, A, Options0, _),
|
||||
( hash_algorithm(A) -> true
|
||||
; 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),
|
||||
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).
|
||||
|
||||
@@ -212,13 +222,19 @@ hash_algorithm(sha256).
|
||||
hash_algorithm(sha512).
|
||||
hash_algorithm(sha384).
|
||||
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.
|
||||
|
||||
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
|
||||
suitable as input keying material and initialization vectors to
|
||||
@@ -227,13 +243,12 @@ hash_algorithm(sha512_256).
|
||||
Admissible options are:
|
||||
|
||||
- algorithm(+Algorithm)
|
||||
A hashing algorithm as specified to crypto_data_hash/3. The
|
||||
default is a cryptographically secure algorithm. If you
|
||||
specify a variable, then it is unified with the algorithm
|
||||
that was used, which is a cryptographically secure algorithm.
|
||||
One of sha256, sha384 or sha512. If you specify a variable,
|
||||
then it is unified with the algorithm that was used, which is a
|
||||
cryptographically secure algorithm by default.
|
||||
- info(+Info)
|
||||
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)
|
||||
Optionally, a list of bytes that are used as salt. The
|
||||
default is all zeroes.
|
||||
@@ -250,15 +265,27 @@ hash_algorithm(sha512_256).
|
||||
|
||||
crypto_data_hkdf(Data0, L, Bytes, Options0) :-
|
||||
functor_hash_options(algorithm, Algorithm, Options0, Options),
|
||||
option(encoding(Encoding), Options, utf8),
|
||||
encoding_bytes(Encoding, Data0, Data),
|
||||
( hkdf_algorithm(Algorithm) -> true
|
||||
; 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, []),
|
||||
must_be_bytes(SaltBytes, crypto_data_hkdf/4),
|
||||
option(info(Info0), Options, []),
|
||||
chars_bytes_(Info0, Info, crypto_data_hkdf/4),
|
||||
'$crypto_data_hkdf'(Data, SaltBytes, Info, Algorithm, L, Bytes).
|
||||
|
||||
hkdf_algorithm(sha256).
|
||||
hkdf_algorithm(sha384).
|
||||
hkdf_algorithm(sha512).
|
||||
|
||||
option(What, Options, Default) :-
|
||||
( member(V, Options), var(V) ->
|
||||
instantiation_error(option/3)
|
||||
; true
|
||||
),
|
||||
( member(What, Options) -> true
|
||||
; What =.. [_,Default]
|
||||
).
|
||||
@@ -379,7 +406,7 @@ crypto_password_hash(Password0, Hash, Options) :-
|
||||
Algorithm = 'pbkdf2-sha512', % current default and only option
|
||||
option(algorithm(Algorithm), Options, Algorithm),
|
||||
( member(salt(SaltBytes), Options) ->
|
||||
true
|
||||
must_be_bytes(SaltBytes, crypto_password_hash/2)
|
||||
; crypto_n_random_bytes(16, SaltBytes)
|
||||
),
|
||||
'$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
|
||||
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.
|
||||
PlainText must be a list of 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)
|
||||
@@ -531,8 +558,7 @@ bytes_base64_([A,B,C|Ls]) --> [W,X,Y,Z],
|
||||
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
|
||||
crypto_data_encrypt(PlainText0, Algorithm, Key, IV, CipherText, Options) :-
|
||||
option(encoding(Encoding), Options, utf8),
|
||||
encoding_bytes(Encoding, PlainText0, PlainText),
|
||||
options_data_bytes(Options, PlainText0, PlainText),
|
||||
option(tag(Tag), Options, _),
|
||||
( nonvar(Tag) ->
|
||||
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
|
||||
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.
|
||||
PlainText. CipherText must be a list of 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.
|
||||
@@ -581,6 +607,8 @@ crypto_data_decrypt(CipherText0, Algorithm, Key, IV, PlainText, Options) :-
|
||||
must_be_bytes(IV, crypto_data_decrypt/6),
|
||||
must_be(atom, Algorithm),
|
||||
option(encoding(Encoding), Options, utf8),
|
||||
must_be(atom, Encoding),
|
||||
member(Encoding, [utf8,octet]),
|
||||
must_be(list, CipherText0),
|
||||
encoding_bytes(octet, CipherText0, CipherText1),
|
||||
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).
|
||||
|
||||
encoding_bytes(octet, Bs0, Bs) :-
|
||||
must_be(list, Bs0),
|
||||
( maplist(integer, Bs0) ->
|
||||
Bs0 = Bs
|
||||
; maplist(char_code, Bs0, Bs)
|
||||
),
|
||||
must_be_bytes(Bs, crypto_encoding).
|
||||
encoding_bytes(utf8, Cs, Bs) :-
|
||||
must_be(list, Cs),
|
||||
( maplist(atom, Cs) ->
|
||||
chars_bytes_(Cs, Bs, crypto_encoding)
|
||||
; 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.
|
||||
|
||||
@@ -49,6 +49,10 @@
|
||||
The predicate format/2 is like format_//2, except that it outputs
|
||||
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
|
||||
that enable easy testing etc. If necessary, you can emit the list Ls
|
||||
with maplist(write, Ls).
|
||||
@@ -68,6 +72,7 @@
|
||||
|
||||
:- module(format, [format_//2,
|
||||
format/2,
|
||||
format/3,
|
||||
portray_clause/1,
|
||||
listing/1
|
||||
]).
|
||||
@@ -359,6 +364,26 @@ format(Fs, Args) :-
|
||||
phrase(format_(Fs, Args), 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).
|
||||
|
||||
|
||||
@@ -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(error)).
|
||||
:- use_module(library(lists), [member/2]).
|
||||
|
||||
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 = []) ->
|
||||
domain_error(source_sink, File, phrase_from_file/2)
|
||||
; '$file_to_chars'(File, Chars),
|
||||
domain_error(source_sink, File, phrase_from_file/3)
|
||||
; 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)
|
||||
).
|
||||
|
||||
@@ -398,7 +398,7 @@ impl MachineState {
|
||||
|
||||
match (n1, n2) {
|
||||
(Number::Fixnum(n1), Number::Fixnum(n2)) => {
|
||||
if n1 != 1 && n2 < 0 {
|
||||
if n1 != 1 && n2 < -1 {
|
||||
let n = Number::from(n1);
|
||||
let stub = MachineError::functor_stub(clause_name!("^"), 2);
|
||||
|
||||
@@ -424,7 +424,7 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
(Number::Fixnum(n1), Number::Integer(n2)) => {
|
||||
if n1 != 1 && &*n2 < &0 {
|
||||
if n1 != 1 && &*n2 < &-1 {
|
||||
let n = Number::from(n1);
|
||||
let stub = MachineError::functor_stub(clause_name!("^"), 2);
|
||||
|
||||
@@ -442,7 +442,7 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
(Number::Integer(n1), Number::Fixnum(n2)) => {
|
||||
if &*n1 != &1 && n2 < 0 {
|
||||
if &*n1 != &1 && n2 < -1 {
|
||||
let n = Number::Integer(n1);
|
||||
let stub = MachineError::functor_stub(clause_name!("^"), 2);
|
||||
|
||||
@@ -460,7 +460,7 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||
if &*n1 != &1 && &*n2 < &0 {
|
||||
if &*n1 != &1 && &*n2 < &-1 {
|
||||
let n = Number::Integer(n1);
|
||||
let stub = MachineError::functor_stub(clause_name!("^"), 2);
|
||||
|
||||
|
||||
@@ -348,7 +348,9 @@ fn compile_into_module(
|
||||
);
|
||||
|
||||
match compile_into_module_impl(wam, &mut compiler, module, src, indices) {
|
||||
Ok(()) => EvalSession::EntrySuccess,
|
||||
Ok(()) => {
|
||||
EvalSession::EntrySuccess
|
||||
}
|
||||
Err(e) => {
|
||||
compiler.drop_expansions(&mut wam.code_repo);
|
||||
EvalSession::from(e)
|
||||
|
||||
@@ -189,6 +189,10 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
#[inline]
|
||||
pub(crate)
|
||||
fn put_complete_string(&mut self, s: &str) -> Addr {
|
||||
if s.is_empty() {
|
||||
return Addr::EmptyList;
|
||||
}
|
||||
|
||||
let addr = self.allocate_pstr(s);
|
||||
self.pop();
|
||||
|
||||
@@ -316,20 +320,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
|
||||
pub(crate)
|
||||
fn allocate_pstr(&mut self, src: &str) -> Addr {
|
||||
self.write_pstr(src)
|
||||
.unwrap_or_else(|| {
|
||||
let h = self.h();
|
||||
|
||||
self.push(HeapCellValue::PartialString(
|
||||
PartialString::empty(),
|
||||
true,
|
||||
));
|
||||
|
||||
self.push(HeapCellValue::Addr(
|
||||
Addr::HeapCell(h + 1)
|
||||
));
|
||||
|
||||
Addr::PStrLocation(h, 0)
|
||||
})
|
||||
.unwrap_or_else(|| Addr::EmptyList)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -1492,9 +1492,13 @@ impl MachineState {
|
||||
&QueryInstruction::PutPartialString(_, ref string, reg, has_tail) => {
|
||||
let pstr_addr =
|
||||
if has_tail {
|
||||
let pstr_addr = self.heap.allocate_pstr(&string);
|
||||
self.heap.pop(); // the tail will be added by the next instruction.
|
||||
pstr_addr
|
||||
if !string.is_empty() {
|
||||
let pstr_addr = self.heap.allocate_pstr(&string);
|
||||
self.heap.pop(); // the tail will be added by the next instruction.
|
||||
pstr_addr
|
||||
} else {
|
||||
Addr::EmptyList
|
||||
}
|
||||
} else {
|
||||
self.heap.put_complete_string(&string)
|
||||
};
|
||||
|
||||
@@ -37,8 +37,8 @@ fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
|
||||
let mut terminator_idx = 0;
|
||||
|
||||
for c in iter {
|
||||
if c == '\u{0}' {
|
||||
break;
|
||||
if c == '\u{0}' && terminator_idx != 0 {
|
||||
return terminator_idx;
|
||||
}
|
||||
|
||||
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)> {
|
||||
let terminator_idx = scan_for_terminator(src.chars());
|
||||
|
||||
if terminator_idx == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let layout = alloc::Layout::from_size_align_unchecked(
|
||||
terminator_idx + '\u{0}'.len_utf8(),
|
||||
mem::align_of::<u8>(),
|
||||
@@ -145,8 +117,8 @@ impl PartialString {
|
||||
|
||||
self.write_terminator_at(terminator_idx);
|
||||
|
||||
Some(if terminator_idx != src.len() {
|
||||
(self, &src[terminator_idx + '\u{0}'.len_utf8() ..])
|
||||
Some(if terminator_idx != src.as_bytes().len() {
|
||||
(self, &src[terminator_idx ..])
|
||||
} else {
|
||||
(self, "")
|
||||
})
|
||||
@@ -211,9 +183,7 @@ impl PartialString {
|
||||
|
||||
#[inline]
|
||||
pub fn at_end(&self, end_n: usize) -> bool {
|
||||
unsafe {
|
||||
ptr::read((self.buf as usize + end_n) as *const u8) == 0u8
|
||||
}
|
||||
end_n + 1 == self.len
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
||||
@@ -688,9 +688,14 @@ impl MachineState {
|
||||
return Err(self.open_past_eos_error(stream.clone(), caller, arity));
|
||||
}
|
||||
EOFAction::EOFCode => {
|
||||
let end_of_stream = self.heap.to_unifiable(
|
||||
HeapCellValue::Atom(clause_name!("end_of_file"), None)
|
||||
);
|
||||
let end_of_stream =
|
||||
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();
|
||||
Ok(self.unify(result, end_of_stream))
|
||||
|
||||
@@ -40,8 +40,10 @@ 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,aead,error};
|
||||
use ring::{digest,hkdf,pbkdf2,aead,signature::{self,KeyPair}};
|
||||
use ripemd160::{Ripemd160, Digest};
|
||||
use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512};
|
||||
use blake2::{Blake2s, Blake2b};
|
||||
|
||||
pub fn get_key() -> KeyEvent {
|
||||
let key;
|
||||
@@ -1110,6 +1112,11 @@ impl MachineState {
|
||||
|
||||
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_tail = self.heap[h + 1].as_addr(h + 1);
|
||||
|
||||
@@ -1154,10 +1161,22 @@ impl MachineState {
|
||||
|
||||
match pstr {
|
||||
Addr::PStrLocation(h, _) => {
|
||||
let tail = self.heap[h + 1].as_addr(h + 1);
|
||||
let target = self[temp_v!(2)];
|
||||
if let HeapCellValue::PartialString(_, true) = &self.heap[h] {
|
||||
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!()
|
||||
@@ -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(
|
||||
buffer.into_iter().map(|b| b as char)
|
||||
);
|
||||
|
||||
self.heap.put_complete_string(&buffer)
|
||||
let type_str = match self.store(self.deref(self[temp_v!(3)])) {
|
||||
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 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);
|
||||
}
|
||||
&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 => {
|
||||
let mut stream =
|
||||
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() {
|
||||
self.eof_action(
|
||||
self[temp_v!(2)],
|
||||
&mut stream,
|
||||
clause_name!("get_byte"),
|
||||
2,
|
||||
)?;
|
||||
|
||||
if EOFAction::Reset != stream.options.eof_action {
|
||||
return return_from_clause!(self.last_call, self);
|
||||
} 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 =
|
||||
match self.store(self.deref(self[temp_v!(2)])) {
|
||||
addr if addr.is_ref() => {
|
||||
@@ -2197,18 +2270,9 @@ impl MachineState {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
self.eof_action(
|
||||
self[temp_v!(2)],
|
||||
&mut stream,
|
||||
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(());
|
||||
}
|
||||
stream.set_past_end_of_stream();
|
||||
self.unify(self[temp_v!(2)], Addr::Fixnum(-1));
|
||||
return return_from_clause!(self.last_call, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5202,21 +5266,39 @@ impl MachineState {
|
||||
};
|
||||
|
||||
let ints_list =
|
||||
if algorithm_str == "ripemd160" {
|
||||
let mut context = Ripemd160::new();
|
||||
context.input(&bytes);
|
||||
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::Integer(Rc::new(Integer::from(*b))))))
|
||||
} else {
|
||||
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::Integer(Rc::new(Integer::from(*b))))))
|
||||
match algorithm_str {
|
||||
"sha3_224" => { let mut context = Sha3_224::new();
|
||||
context.input(&bytes);
|
||||
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
|
||||
"sha3_256" => { let mut context = Sha3_256::new();
|
||||
context.input(&bytes);
|
||||
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
|
||||
"sha3_384" => { let mut context = Sha3_384::new();
|
||||
context.input(&bytes);
|
||||
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
|
||||
"sha3_512" => { let mut context = Sha3_512::new();
|
||||
context.input(&bytes);
|
||||
Addr::HeapCell(self.heap.to_list(context.result().as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize))))) }
|
||||
"blake2s256" => { let mut context = Blake2s::new();
|
||||
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);
|
||||
@@ -5248,11 +5330,12 @@ impl MachineState {
|
||||
usize::try_from(n).unwrap()
|
||||
}
|
||||
Ok(Number::Integer(n)) => {
|
||||
n.to_usize().unwrap()
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
match n.to_usize() {
|
||||
Some(u) => { u }
|
||||
_ => { self.fail = true; return Ok(()); }
|
||||
}
|
||||
}
|
||||
_ => { unreachable!() }
|
||||
};
|
||||
|
||||
let ints_list =
|
||||
@@ -5261,14 +5344,17 @@ impl MachineState {
|
||||
"sha256" => { hkdf::HKDF_SHA256 }
|
||||
"sha384" => { hkdf::HKDF_SHA384 }
|
||||
"sha512" => { hkdf::HKDF_SHA512 }
|
||||
_ => { unreachable!() }
|
||||
_ => { self.fail = true; return Ok(()); }
|
||||
};
|
||||
let salt = hkdf::Salt::new(digest_alg, &salt);
|
||||
let mut bytes : Vec<u8> = Vec::new();
|
||||
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);
|
||||
@@ -5285,7 +5371,10 @@ impl MachineState {
|
||||
u64::try_from(n).unwrap()
|
||||
}
|
||||
Ok(Number::Integer(n)) => {
|
||||
n.to_u64().unwrap()
|
||||
match n.to_u64() {
|
||||
Some(i) => { i }
|
||||
None => { self.fail = true; return Ok(()); }
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
@@ -5298,7 +5387,7 @@ impl MachineState {
|
||||
NonZeroU32::new(iterations as u32).unwrap(), &salt,
|
||||
&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);
|
||||
@@ -5312,18 +5401,18 @@ impl MachineState {
|
||||
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 nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
|
||||
let key = aead::LessSafeKey::new(unbound_key);
|
||||
|
||||
let mut in_out = data.clone();
|
||||
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 }
|
||||
_ => { 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))))));
|
||||
Addr::HeapCell(self.heap.to_list(tag.as_ref().iter().map(|b| HeapCellValue::from(Addr::Fixnum(*b as isize)))));
|
||||
|
||||
let complete_string = {
|
||||
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 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 nonce = aead::Nonce::try_assume_unique_for_key(&iv).unwrap();
|
||||
let key = aead::LessSafeKey::new(unbound_key);
|
||||
|
||||
let mut in_out = data.clone();
|
||||
|
||||
let complete_string = {
|
||||
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 }
|
||||
_ => { self.fail = true; return Ok(()); }
|
||||
};
|
||||
@@ -5382,6 +5471,63 @@ impl MachineState {
|
||||
|
||||
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)
|
||||
@@ -5406,17 +5552,3 @@ 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