# Samples Overview

See `../sampling/top.lisp` for an overview of sampling and samples.

This directory contains R1CS samples extracted from snarkVM, in various forms,
from raw `cargo test` output to ACL2 representation of R1CS.

To save space for ACL2 users who are not interested in snarkVM samples, we use
`git lfs`(*) on selected zipped files.  Prior to the current directory being
committed (as of 2025-06-24), a freshly-cloned ACL2 takes about 2.6 GB of space.
If the large files in this directory were not in `git lfs`, all users would see
an additional 50 MB clone size, a 2% increase.  As it is now, users without `git
lfs` installed will simply see stub files instead of the large zipped files.

(*) [Github's support of Git LFS is described here.](https://docs.github.com/en/repositories/working-with-files/managing-large-files/about-git-large-file-storage)

Enough smaller samples in ACL2 form remain uncompressed so that they can be
checked against the ACL2 models as part of the ACL2 books regression test.

If you would like to examine all the samples, you will need to have `git lfs`
installed.  You can then clone ACL2 to get all the files including those in LFS,
or do `git lfs pull` to replace the stubs by the full zip files.
You can then unzip the files of interest to get the full contents.
Note, the samples/raw directory contents have been zipped into a single file
for convenience.

# Historical Notes

## Processing R1CS Samples

* To generate the files in the `raw/` subdirectory see `raw/README.md`.

* A raw file is then turned into an ACL2 _message JSON_ file with one `defconst` for each serialized circuit.
  Currently the definitions are simply serialized JSON strings; the plan is to do more processing
  at this step.  An example of a _message JSON_ file is `./u64-message-json-auto.lisp`.
  As you can see at the top of that file, there is a comment that shows how the file
  was generated.  (The comment was also generated by that call.)

* A _message JSON_ defconst can then be converted to an `r1cs::r1cs-constraint-listp`
  using the function `aleo::json-message-group-string-to-constraints`.  Some example calls to this function
  are in `./u64-samples.lisp`, where the resulting constraint lists are compared to constraint lists
  instantiated from circuit specs that are defined in `../r1cs/` or `../pfcs/`.

## Checking R1CS Samples

In order to check R1CS sample correctness, we need a specification of what is correct.

First, we describe what the R1CS is supposed to do at a high level in a formal language.
We will call this the **_high-level specification_**, or just *specification* for short.
For example, for the circuit that does field exponentiation (field ** field),
the ACL2 specification is already part of the Prime Fields library and can
stated with `(pfield::pow x n p)`, where `p` is a prime, `x` is an
element of the prime field 𝚭/𝚭p (the integers modulo p) and `n` is any natural number.

Second, we create an **_ACL2 circuit definition_**, describing the shape of the R1CS.
This circuit definition is similar to the SnarkVM definition, but is generalized
(1) over the R1CS variables and (2) with other parameters that define a family of
related R1CSes, if appropriate. For example, for integer circuits, the
bit width is a parameter, so if a new size of integer types is added
to Aleo Instructions later the ACL circuit definition can be reused.

An ACL2 circuit definition is checked against a snarkVM R1CS sample as follows.
The snarkVM R1CS sample is converted to ACL2 R1CS as described above.
The ACL2 circuit definition is instantiated with corresponding variable names
and we make sure the resulting R1CS is equal to the the R1CS from snrkVM.

A single Aleo Instruction Opcode may require multiple ACL2 circuit definitions,
based on whether its arguments are variable or constant.
For example, an Aleo Instruction field exponentiation requires different ACL2 circuit
definitions for the `(variable ** variable)`, `(constant ** variable)`, and
`(variable ** constant)` cases.  Each of the ACL2 circuit definitions takes the prime `p`
as an input.  In operations involving a constant, the constant is also an input
to the circuit definition, so we can describe different R1CSes for different constants.

We also formally verify that the high-level specification is semantically equivalent
to the ACL2 circuit definition.  (Although this is of critical importance,
it is not the focus of this page, so we do not get into the details here.)
After that, we know if any sample from SnarkVM equals an appropriate instantiation
of the ACL2 circuit definition, then we know the R1CS correctly implements the
high-level specification.

Here is information on snarkVM samples we have captured and the status of
checking them against ACL2 circuit definitions.

<!--
As far as it goes, this is correct as of 2023-04-29.  But there is more not yet entered.
When we are up to date with the current status, we should put in the right date here and remove the comment.

Also, consider moving some of this discussion up a level, to circuits/README.md
and just having this file be more sample-specific info.
-->

This first table shows the files in snarkVM (branch "formal") that extract samples,
along with the corresponding _raw_ files (which contain the date captured in the file name),
and _message JSON_ files as described at the top of this file.

| snarkVM Sample Category | file in snarkVM | raw file in aleo-acl2 | message JSON file in aleo-acl2 |
| ----------------------- | --------------- | --------------------- | ------------------------------ |
| field | circuit/tests/field.rs | circuits/samples/raw/field-2023-04-19.txt | circuits/samples/field-message-json-auto-staging.lisp and circuits/samples/field-message-json-auto-staging-mod.lisp[^1]. |
| u64 | circuit/tests/integers.rs | circuits/samples/raw/u64-2023-04-21.txt | circuits/samples/u64-message-json-auto-staging.lisp |

[^1]: The "-mod" version has some "-new" circuits.  This is temporary.

Note, there are some older samples that we checked, and some of those checks
are still in the aleo-acl2 build, but we will not necessarily maintain those
going forward.

This next tables show the status of checking each sample.
Each table is for a category of samples.

### Field samples

In the file [aleo-acl2/circuits/samples/field-samples.lisp](./field-samples.lisp),
each sample is converted to ACL2 R1CS format, and a nullary function is defined that
returns the list of constraints.  (That is usually easier to use for proofs
than a defconst is.  Another note is that previous generations of samples were
converted differently.)

The **Sample Name** column omits `field::`.

Note, if there are both "-new" and old non-"-new" versions, the plan is
to get rid of the old non-"-new" version and then rename "-new" to replace
the old one.

Another note, most of these tables are done, they just need to be filled in more.

All file names in the table are relative to `aleo-acl2/circuits/`.

| Sample Name | ACL2 circuit defn. file | verif?[^2]. | checking file[^3]. | notes |
| ----------- | ---------------------- | ----------- | ------------------ | ----- |
| add | none[^4]. |
| compare | r1cs/field-lt.lisp | :heavy_check_mark: | samples/field-compare.lisp
| compare-new | r1cs/field-lt-new.lisp | :heavy_check_mark: | samples/field-compare-new.lisp
| div | r1cs/field-div.lisp | :heavy_check_mark: | samples/field-div.lisp | verify oppt.[^6].
| div_unchecked |||| This is not an opcode[^7].
| double | none[^4]. |
| eq/neq | r1cs/field-neq.lisp | :heavy_check_mark: | samples/field-neq.lisp | we will separate eq from neq in PFCS circuits
| from_bits_le | r1cs/field-from-bits.lisp | :heavy_check_mark: | samples/field-from-bits-le.lisp
| from_bits_le-new | r1cs/field-from-bits-new.lisp | :heavy_check_mark: | samples/field-from-bits-new.lisp
| from_bits_le_diff_const | r1cs/bits-lte-const.lisp | :heavy_check_mark: | samples/field-from-bits-new.lisp
| inverse | r1cs/field-inverse.lisp | :heavy_check_mark: | samples/field-inverse.lisp
| mul | r1cs/field-mul.lisp | :heavy_check_mark: | samples/field-mul.lisp
| neg | none[^4]. |
| pow10 | r1cs/field-pow-const.lisp | :heavy_check_mark: | samples/field-pow.lisp | do: get more samples, 7 and (2^100 + 3)
| cBIGNUMpow[^5]. | r1cs/field-const-pow.lisp | :heavy_check_mark: | samples/field-pow.lisp |
| c15pow | r1cs/field-const-pow.lisp | :heavy_check_mark: | samples/field-pow.lisp |
| c11pow | r1cs/field-const-pow.lisp | :heavy_check_mark: | samples/field-pow.lisp |
| c6pow | r1cs/field-const-pow.lisp | :heavy_check_mark: | samples/field-pow.lisp |
| c1pow | r1cs/field-const-pow.lisp | :heavy_check_mark: | samples/field-pow.lisp |
| c0pow | r1cs/field-const-pow.lisp | :heavy_check_mark: | samples/field-pow.lisp |
| pow | r1cs/field-pow-new.lisp | :heavy_check_mark: | samples/field-pow.lisp
| square | r1cs/field-square.lisp | :heavy_check_mark: | samples/field-square.lisp
| square_root |||| circuit will be changed soon---revisit at that time
| sub | none[^4]. |
| ternary | r1cs/field-ternary.lisp | :heavy_check_mark: | samples/field-ternary.lisp
| to_bits_le | r1cs/field-to-bits.lisp | :heavy_check_mark: | samples/field-to-bits-le.lisp
| to_bits_le-new | r1cs/field-to-bits-new.lisp | :heavy_check_mark: | samples/field-to-bits-le-new.lisp
| | |

### Integer samples

Note, bookkeeping sample progress has been moved elsewhere.

### Footnotes

[^2]: An "x" in this column means the ACL2 circuit definition has been formally verified against the high-level specification, at least in terms of soundness.
[^3]: File instantiating the ACL2 circuit definition and showing equivalence to the sample.
[^4]: "none" means that the operation can be done in a linear combination without creating a constraints.  SnarkVM directly modifies the linear combinations instead of adding a constraint.
[^5]: BIGNUM = (2**252 - 1) = 7237005577332262213973186563042994240829374041602535252466099000494570602495
[^6]: the field div opcode gets an error (constraint system can't be satisfied) if y is zero.  We want to be able to describe this in a spec and to include the concept in the proof of spec/circuit equivalence.  r1cs/field-div.lisp has a trial version of that.
[^7]: the div_unchecked circuit is an internal circuit that is not attached to an Aleo Instructions opcode, which is good, because it would introduce nondeterminism.  When it is used as a subcircuit, it must be used with the obligation that if x and y are both zero, z must be constrained in some other way or unused by the output, or the composite circuit can be unsound.  The formal model of circuit composition must capture this concept.
