@@ -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"
|
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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
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
|
## 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 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 string.
|
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.
|
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 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
|
||||||
|
|||||||
@@ -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))),
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,11 @@
|
|||||||
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,
|
||||||
@@ -21,6 +25,10 @@
|
|||||||
crypto_password_hash/3, % +Password, -Hash, +Options
|
crypto_password_hash/3, % +Password, -Hash, +Options
|
||||||
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
|
crypto_data_encrypt/6, % +PlainText, +Algorithm, +Key, +IV, -CipherText, +Options
|
||||||
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
|
crypto_data_decrypt/6, % +CipherText, +Algorithm, +Key, +IV, -PlainText, +Options
|
||||||
|
ed25519_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_name_curve/2, % +Name, -Curve
|
||||||
crypto_curve_order/2, % +Curve, -Order
|
crypto_curve_order/2, % +Curve, -Order
|
||||||
crypto_curve_generator/2, % +Curve, -Generator
|
crypto_curve_generator/2, % +Curve, -Generator
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
).
|
).
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
if !string.is_empty() {
|
||||||
let pstr_addr = self.heap.allocate_pstr(&string);
|
let pstr_addr = self.heap.allocate_pstr(&string);
|
||||||
self.heap.pop(); // the tail will be added by the next instruction.
|
self.heap.pop(); // the tail will be added by the next instruction.
|
||||||
pstr_addr
|
pstr_addr
|
||||||
|
} else {
|
||||||
|
Addr::EmptyList
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
self.heap.put_complete_string(&string)
|
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;
|
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]
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
if stream.options.stream_type == StreamType::Binary {
|
||||||
|
Addr::Fixnum(-1)
|
||||||
|
} else {
|
||||||
|
self.heap.to_unifiable(
|
||||||
HeapCellValue::Atom(clause_name!("end_of_file"), None)
|
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))
|
||||||
|
|||||||
@@ -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, _) => {
|
||||||
|
if let HeapCellValue::PartialString(_, true) = &self.heap[h] {
|
||||||
let tail = self.heap[h + 1].as_addr(h + 1);
|
let tail = self.heap[h + 1].as_addr(h + 1);
|
||||||
let target = self[temp_v!(2)];
|
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,15 +1907,36 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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 complete_string = {
|
||||||
let mut buffer = String::new();
|
let mut buffer = String::new();
|
||||||
match file.read_to_string(&mut buffer) {
|
match type_str {
|
||||||
|
"text" => { match file.read_to_string(&mut buffer) {
|
||||||
Ok(_size) => {
|
Ok(_size) => {
|
||||||
self.heap.put_complete_string(&buffer)
|
self.heap.put_complete_string(&buffer)
|
||||||
}
|
}
|
||||||
Err(_e) => {
|
Err(_e) => {
|
||||||
// This case if the data isn't UTF-8 valid.
|
// the data isn't valid UTF-8, so we fail.
|
||||||
let mut buffer = Vec::new();
|
self.fail = true;
|
||||||
|
return Ok(());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"binary" => { let mut buffer = Vec::new();
|
||||||
let _ = match file.read_to_end(&mut buffer) {
|
let _ = match file.read_to_end(&mut buffer) {
|
||||||
Ok(size) => size,
|
Ok(size) => size,
|
||||||
Err(_e) => unreachable!()
|
Err(_e) => unreachable!()
|
||||||
@@ -1908,6 +1948,7 @@ impl MachineState {
|
|||||||
|
|
||||||
self.heap.put_complete_string(&buffer)
|
self.heap.put_complete_string(&buffer)
|
||||||
}
|
}
|
||||||
|
_ => { unreachable!() }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -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,
|
|
||||||
clause_name!("get_byte"),
|
|
||||||
2,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
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 {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5202,12 +5266,29 @@ 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);
|
||||||
|
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 {
|
match algorithm_str {
|
||||||
"sha256" => { &digest::SHA256 }
|
"sha256" => { &digest::SHA256 }
|
||||||
"sha384" => { &digest::SHA384 }
|
"sha384" => { &digest::SHA384 }
|
||||||
@@ -5216,7 +5297,8 @@ impl MachineState {
|
|||||||
_ => { unreachable!() }
|
_ => { unreachable!() }
|
||||||
},
|
},
|
||||||
&bytes);
|
&bytes);
|
||||||
Addr::HeapCell(self.heap.to_list(ints.as_ref().iter().map(|b| HeapCellValue::Integer(Rc::new(Integer::from(*b))))))
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user