Skip to content

Commit

Permalink
Merge branch 'main' into igor/bug1133
Browse files Browse the repository at this point in the history
  • Loading branch information
konnov authored Sep 12, 2023
2 parents e34875d + 5a36609 commit f5852ca
Show file tree
Hide file tree
Showing 31 changed files with 12,593 additions and 12,187 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## UNRELEASED

### Added

- Added `--temporal` flag for `verify`, enabling temporal property verification
through Apalache (#1154)

### Changed

- Introduce frames on actions in the verbose output. The verbose output has changed! (#1158)
Expand All @@ -17,6 +21,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
### Security

## v0.14.2 -- 2023-09-06

### Added
### Changed
### Deprecated
### Removed
### Fixed

- Fixed a problem where importing the same definition under multiple different
names would cause a crash (#1142)
- Fixed a problem where importing a module in the REPL would prevent state
variables from having their values persisted between evaluations (#1146)

### Security

## v0.14.1 -- 2023-08-28

### Added
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,8 @@ completely implementing every pass.
| Invariant checking | - | - | - | - | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [Higher-order definitions][] | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
| [Runs][] | :white_check_mark: | :white_check_mark: | :green_circle: | :white_check_mark: | :white_check_mark: | *non-goal* | :white_check_mark: |
| [Temporal operators][] | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | *non-goal* | :x: | :x: |
| [Fairness][] | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | *non-goal* | :x: | :x: |
| [Temporal operators][] | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | *non-goal* | :white_check_mark: | :x: |
| [Fairness][] | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | *non-goal* | :white_check_mark: | :x: |
| [Unbounded quantifiers][] | :white_check_mark: | :white_check_mark: | :x: | :x: | *non-goal* | :x: | :x: |
| [String literals][], see #118 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| ~~uninterpreted types~~, see #118 | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: |
Expand Down
2 changes: 1 addition & 1 deletion doc/builtin.md
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ assert(List(1, 2, 3).select(x -> x % 2 == 0) == List(2))

## `pure def foldl: (List[a], b, (b, a) => b) => b`

`l.foldl(z, f)` reduces the elements in `s` using `f`,
`l.foldl(z, f)` reduces the elements in `l` using `f`,
starting with `z` from the left.

I.e., `f(f(f(z, x0), x1)..., xn)`.
Expand Down
30 changes: 17 additions & 13 deletions doc/quint.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,20 +274,25 @@ Options:
[number] [default: 10]
--init name of the initializer action [string] [default: "init"]
--step name of the step action [string] [default: "step"]
--invariant invariant to check: a definition name or an expression
--invariant the invariants to check, separated by a comma [string]
--temporal the temporal properties to check, separated by a comma
[string]
--apalache-config Filename of the additional Apalache configuration (in the
HOCON format, a superset of JSON) [string]
--verbosity control how much output is produced (0 to 5)
[number] [default: 2]
```
<!-- TODO: Update after https://github.com/informalsystems/quint/issues/701 -->
Use of this command has three prerequisites:
By default, this command will automatically obtain and run Apalache. The only
prerequisite is a [compatible installation of OpenJDK](quint/README.md).
You may also manually obtain and run a distribution of Apalache, following these
steps:
1. Install a distribution of [Apalache](https://apalache.informal.systems/docs/apalache/installation/jvm.html).
2. Start the Apalache server `apalache-mc server` and ensure that it is running.
1. You have installed a distribution of
[Apalache](https://apalache.informal.systems/docs/apalache/installation/jvm.html)
2. You have set `APALACHE_DIST` as the path to the distribution.
3. You have started the Apalache server `apalache-mc server` and it is running.
Apalache uses bounded model checking. This technique checks *all runs* up to
`--max-steps` steps via [z3][]. Apalache is highly configurable. See [Apalache
configuration](https://apalache.informal.systems/docs/apalache/config.html?highlight=configuration#apalache-configuration)
Expand All @@ -296,12 +301,11 @@ for guidance.
- If there are no critical errors (e.g., in parsing, typechecking, etc.), this
command sends the Quint specification to the [Apalache][] model checker, which
will try to find an invariant violation. If it finds one, it prints the trace on
the standard output. If it does not find a violating trace, it prints the
longest sample trace that the simulator has found during the execution. When the
parameter `--out` is supplied, the trace is written as a JSON representation of
Quint IR in the output file. When the parameter `--out-itf` is supplied, the
trace is written in the [Informal Trace Format][]. This output can be
conveniently displayed with the [ITF Trace Viewer][], or just with [jq][].
the standard output. When the parameter `--out` is supplied, the trace is
written as a JSON representation of Quint IR in the output file. When the
parameter `--out-itf` is supplied, the trace is written in the [Informal Trace
Format][]. This output can be conveniently displayed with the [ITF Trace
Viewer][], or just with [jq][].
- If the specification cannot be run (e.g., due to a parsing error), the file
contains an error message in JSON:
Expand Down
18 changes: 18 additions & 0 deletions editor-plugins/emacs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Emacs support

We have 2 packages for enabling support for Quint in Emacs.

1. `quint-mode` is a major mode that enables simple syntax highlighting
2. `lsp-quint` is a client for `lsp-mode`, enabling IDE features provided by `quint-language-server`

These packages are not published anywhere for the moment. You can clone this git repo and add a configuration like the following (which uses `use-package`):

```elisp
(load-file "<path-to-quint-repo>/editor-plugins/emacs/quint-mode.el")
(load-file "<path-to-quint-repo>/editor-plugins/emacs/lsp-quint.el")
(require 'quint-mode)
(add-to-list 'auto-mode-alist '("\\.qnt" . quint-mode))
(use-package lsp-quint
:ensure t
:hook (quint-mode . lsp))
```
56 changes: 56 additions & 0 deletions editor-plugins/emacs/lsp-quint.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
;;; lsp-quint.el --- Quint LSP Client settings
;;;
;; Copyright (C) 2023 Gabriela Moreira

;; Author: Gabriela Moreira ([email protected])
;; URL: https://github.com/informalsystems/quint
;; Version: 1.0.0
;; Created: 28 Aug 2023
;; Updated 21 Aug 2023
;; Keywords: languages

;; This file is not part of GNU Emacs.

;;; Commentary:

;; A client for lsp-mode for the Quint Specification Language, using the quint language server.

;;; Code:

(require 'lsp-mode)
(require 'lsp-completion)

(defgroup lsp-quint nil
"LSP support for the Quint Specification Language, using the quint language server."
:link '(url-link "https://github.com/informalsystems/quint")
:group 'lsp-mode
:package-version '(lsp-mode . "6.3.2"))

(lsp-dependency 'quint-language-server
'(:system "quint-language-server")
'(:npm :package "@informalsystems/quint-language-server"
:path "quint-language-server"))

(add-to-list 'lsp-language-id-configuration '(quint-mode . "quint"))
(lsp-register-client
(make-lsp-client :new-connection (lsp-stdio-connection
(lambda () (list (lsp-package-path 'quint-language-server) "--stdio")))
:major-modes '(quint-mode)
:activation-fn (lsp-activate-on "quint")
:language-id "quint"
:priority 0
:server-id 'quint-language-server
:completion-in-comments? t
:download-server-fn (lambda (_client callback error-callback _update?)
(lsp-package-ensure
'quint-language-server
(-partial #'lsp-package-ensure
'quint-language-server
callback
error-callback)
error-callback))))

(lsp-consistency-check lsp-quint)

(provide 'lsp-quint)
;;; lsp-quint.el ends here
4 changes: 3 additions & 1 deletion examples/.scripts/run-example.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ result () {
"$file" == "cosmos/tendermint/Tendermint.qnt" ||
"$file" == "cosmos/tendermint/TendermintTest.qnt" ||
"$file" == "cosmos/lightclient/Blockchain.qnt" ||
"$file" == "cosmos/lightclient/LCVerificationApi.qnt" ) ]] ; then
"$file" == "cosmos/lightclient/LCVerificationApi.qnt" ||
"$file" == "cryptography/hashes.qnt" ) ]] ; then
printf "N/A[^parameterized]"; return
fi
# Skip verification for specs that do not define a state machine
Expand All @@ -28,6 +29,7 @@ result () {
"$file" == "cosmos/lightclient/typedefs.qnt" ||
"$file" == "cosmos/tendermint/Tendermint.qnt" ||
"$file" == "cosmos/tendermint/TendermintTest.qnt" ||
"$file" =~ ^cryptography/ ||
"$file" =~ ^spells/ ||
"$file" == "solidity/SimpleAuction/SimpleAuction.qnt" ||
"$file" == "cosmos/ics20/base.qnt" ) ]] ; then
Expand Down
2 changes: 2 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ listed without any additional command line arguments.
| [cosmos/tendermint/TendermintModels.qnt](./cosmos/tendermint/TendermintModels.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [cosmos/tendermint/TendermintTest.qnt](./cosmos/tendermint/TendermintTest.qnt) | :white_check_mark: | :white_check_mark: | N/A[^parameterized] | N/A[^nostatemachine] |
| [cosmwasm/zero-to-hero/vote.qnt](./cosmwasm/zero-to-hero/vote.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x:<sup>https://github.com/informalsystems/quint/issues/693</sup> |
| [cryptography/hashes.qnt](./cryptography/hashes.qnt) | :white_check_mark: | :white_check_mark: | N/A[^parameterized] | N/A[^nostatemachine] |
| [cryptography/hashesTest.qnt](./cryptography/hashesTest.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | N/A[^nostatemachine] |
| [language-features/booleans.qnt](./language-features/booleans.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [language-features/counters.qnt](./language-features/counters.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| [language-features/importFrom.qnt](./language-features/importFrom.qnt) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
Expand Down
90 changes: 90 additions & 0 deletions examples/cryptography/hashes.qnt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* The module `hashes` provides the standard means of hashing byte sequences in
* Quint. A direct implementation of a hash (e.g., of SHA256) in Quint would
* produce plenty of hard-to-solve arithmetic constraints in a Quint
* specification. To this end, we introduce a different specification of a hash
* that has the following important properties:
*
* 1. For two sequences of bytes `bs1` and `bs2`, it holds that `bs1 == bs2` if
* and only if `hash(bs1) == hash(bs2)`. That is, our hash is perfect, it does
* not produce any collisions.
*
* 2. Hashes can be nested, e.g., `hash(hash(bs1).hconcat(bs2))`. Nested hashes
* preserve the property (1).
*
* 3. The operator `hlen` computes the length of byte sequences, some of
* which may have been computed via `hash`.
*
* 4. Plain text byte sequences and hashes may be concatenated via `hconcat`.
*
* Importantly, this modeling does not guarantee that a byte sequence would look
* exactly the same, as if it was computed via a real hash implementation.
* We will introduce integration with actual hash implementations later.
*
* Igor Konnov, Informal Systems, 2023.
*/
module hashes {
/// the length of a hashed sequence in bytes, e.g., 32 for SHA-256.
const HASH_LEN: int

/// A data structure that carries plain texts and hashed texts.
/// We could simply use `List[int]`, but a designated type indicates that
/// the user should not look inside.
type HMessage = {
_bytes: List[int]
}

/// Construct HText from plain text, that is, a list of bytes.
///
/// @param bytes the input to wrap, all list elements shall be in the range
/// of [0, 255].
/// @returns the HMessage representation of bytes
pure def hplain(bytes: List[int]): HMessage = {
{ _bytes: bytes }
}

/// Concatenate two messages, possibly hashed.
///
/// @param first the first message
/// @param second the second message
/// @returns new message, in which `second` follows `first`.
pure def hconcat(first: HMessage, second: HMessage): HMessage = {
{ _bytes: first._bytes.concat(second._bytes) }
}

/// Hash a sequence of bytes, some of which may have been hashed already.
///
/// @param input the input to hash
/// @returns the hashed sequence of bytes
pure def hash(input: HMessage): HMessage = {
// We simply wrap the whole sequence of bytes with two markers -1.
// Since some parts of the input may have been hashed already, we decrease
// the hash markers in `input._bytes` first.
pure val decreased: List[int] = input._bytes.foldl([],
(l, b) => l.append(if (b >= 0) b else (b - 1))
)
// wrap with the markers -1
{ _bytes: [-1].concat(decreased).append(-1) }
}

/// Compute the length of a message that may contain hashes or just plain text
///
/// @param input the input to calculate the length of
/// @returns the length of the sequence
pure def hlen(input: HMessage): int = {
input._bytes.foldl((0, false),
(p, b) =>
if (b == -1) {
val newLen = p._1 + if (p._2) HASH_LEN else 0 // We add the total hash length at the terminator
(newLen, not(p._2)) // toggle the "in hash" flag
} else {
val newLen = p._1 + if (p._2) 0 else 1 // if in hash, the total hash length gets added in the terminator
(newLen, p._2)
}
)._1
}
}

module sha256 {
import hashes(HASH_LEN = 32).*
}
37 changes: 37 additions & 0 deletions examples/cryptography/hashesTest.qnt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module hashesTest {
import hashes(HASH_LEN = 32).* from "./hashes"

pure def hplainTest = and {
assert(hplain([ 2, 3, 4 ]) == hplain([ 2, 3, 4 ])),
assert(hplain([ 2, 3, 4 ]) != hplain([ 3, 4, 5 ])),
}

pure def hashTest = and {
assert(hash(hplain([ 2, 3, 4 ])) == hash(hplain([ 2, 3, 4 ]))),
assert(hash(hplain([ 2, 3, 4 ])) != hash(hplain([ 3, 4, 5 ]))),
assert(hash(hplain([ 2, 3, 4 ])) != hplain([ 2, 3, 4 ])),
assert(hash(hash(hplain([ 2, 3, 4 ]))) != hash(hplain([ 2, 3, 4 ]))),
}

pure def hconcatTest = and {
pure val t234then567 = hplain([ 2, 3, 4 ]).hconcat(hplain([ 5, 6, 7 ]))
pure val t234567 = hplain([ 2, 3, 4, 5, 6, 7 ])
assert(t234then567 == t234567),
pure val h234then567 = hash(hplain([ 2, 3, 4 ])).hconcat(hplain([ 5, 6, 7 ]))
assert(h234then567 != hplain([ 2, 3, 4, 5, 6, 7 ])),
pure def l =
(hash(hplain([ 2, 3, 4 ])).hconcat(hplain([ 5, 6, 7 ]))).hconcat(hplain([ 8, 9 ]))
pure def r =
hash(hplain([ 2, 3, 4 ])).hconcat((hplain([ 5, 6, 7 ])).hconcat(hplain([ 8, 9 ])))
assert(l == r),
}

pure def hlenTest = and {
assert(hlen(hash(hplain([ 2, 3, 4 ]))) == 32),
assert(hlen(hash(hash(hplain([ 2, 3, 4 ])))) == 32),
assert(hlen(hplain([ 2, 3, 4, 5, 6, 7 ])) == 6),
pure def l =
(hash(hplain([ 2, 3, 4 ])).hconcat(hplain([ 5, 6, 7 ]))).hconcat(hplain([ 8, 9 ]))
assert(hlen(l) == 37)
}
}
4 changes: 2 additions & 2 deletions examples/solidity/GradualPonzi/gradualPonzi.qnt
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ module gradualPonziTest {
//
// If quint has not reported a violation, try:
//
// $ quint run --invariant=progressInv --main=gradualPonziTest --seed=0x8385bfe3a7497 gradualPonzi.qnt
// $ quint run --invariant=progressInv --main=gradualPonziTest --max-steps=50 --seed=0x8272b36d6a57f gradualPonzi.qnt
//
// It is quite hard for `quint run` to find a violation to this property.
// In contrast, `quint verify` finds it in a few seconds.
Expand All @@ -254,4 +254,4 @@ module gradualPonziTest {
val sumRewards = addr.fold(0, (s, a) => s + ponziState.rewards.get(a))
sumRewards == evmState.balances.get("contract")
}
}
}
Loading

0 comments on commit f5852ca

Please sign in to comment.