Skip to content

Commit

Permalink
add comments and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkenan committed Jul 14, 2023
1 parent db82f23 commit b69158d
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 5 deletions.
29 changes: 26 additions & 3 deletions docs/rust-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,33 @@ These are the relevant files:

## Compiling

The rust package can be compiled by moving to the `lib/lambdaworks` directory and executing `cargo build --release`. This produces a `lib/lambdaworks/target/liblambdaworks.a` file that will be imported by the `lambdaworks.go` as a static library, as we can see in the comment over the `Number` function.
The rust package can be compiled by moving to the `lib/lambdaworks` directory and executing `cargo build --release`. This produces a `lib/lambdaworks/target/liblambdaworks.a` file that is, in turn, imported by `lambdaworks.go` as a static library, as we can see in the comment over the `Number` function.

In `Makefile` we can see that one of the steps is actually moving to the rust project, compiling, and then copying the archive file to the `lib` directory so it can be consumed by the go code.

## Next steps:
## FFI

FFI is a way of having calls between C and rust. To allow this we have two key steps:
- Wrapping function calls (with `no_mangle`` modifier) and adding a header file to make them available to C.
- Making sure that all data structures can be represented in C.

`lambdaworks.h` is the file containing all of the function wrappers around the field element type. As FieldElement and all its variants are already defined in lambdaworks and do not conform
to the C memory layout we need to have our own representation with the `repr(C)` modifier.
Internally, field elements are represented by an array of four integers called "limbs", using
montgomery representation, and do not contain any extra data. For simplicity, we then choose to
represent them in C as that array, and `felt_t` is just an alias for an unsigned 64 bit integer array with four elements.

As we can't return arrays in C, any rust function that returns a felt (one, zero, from, mul, add, etc) has a `result` with a raw pointer that is written instead. Memory allocation can happen
statically in C, as they will always be 4-element arrays.

`lib.rs` mostly does, for every wrapper function:
- Convert argument felts (limb arrays) to rust felts.
- Call the wrapped operation
- Convert the result back to limbs representation in the result parameter.

## Limbs representation

We need to take into account that we take the `felt.representative()` limbs instead of `felt.value().limbs` version, as the latter is in montgomery representation. If we took that one
instead, when building the `UnsignedInteger<4> struct` we'll be representing a different number.
When constructiong the `FieldElement` from that, the montgomery algorithm will be applied even if the data is already in that representation, effectively building a Felt that represents a different number.

The lambdaworks math and crypto rust dependencies are already included in the `Cargo.toml`, but they are not used. The first step would be to add a wrapper that manipulates the finite field type instead of a simple integer.
17 changes: 16 additions & 1 deletion pkg/lambdaworks/lib/lambdaworks.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
#include <stdint.h>

/* A single limb (unsigned integer with 64 bits). */
typedef uint64_t limb_t;

/* A 256 bit prime field element (felt), represented as four limbs (integers). */
typedef limb_t felt_t[4];

int number();
/* Gets a felt_t representing the "value" number, in montgomery format. */
void from(felt_t result, uint64_t value);

/* Gets a felt_t representing 0 */
void zero(felt_t result);

/* Gets a felt_t representing 1 */
void one(felt_t result);

/* Writes the result variable with the sum of a and b felts. */
void add(felt_t a, felt_t b, felt_t result);

/* Writes the result variable with a - b. */
void sub(felt_t a, felt_t b, felt_t result);

/* Writes the result variable with a * b. */
void mul(felt_t a, felt_t b, felt_t result);

/* Writes the result variable with a / b. */
void div(felt_t a, felt_t b, felt_t result);
1 change: 0 additions & 1 deletion pkg/lambdaworks/lib/lambdaworks/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ edition = "2021"
[dependencies]
libc = "0.2"
lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git" }
lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks.git" }

[lib]
crate-type = ["cdylib", "staticlib", "lib"]
10 changes: 10 additions & 0 deletions pkg/lambdaworks/lib/lambdaworks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@ use lambdaworks_math::{
unsigned_integer::element::UnsignedInteger,
};

// A 256 bit prime field represented as a Montgomery, 4-limb UnsignedInteger.
type Felt = FieldElement<Stark252PrimeField>;

// C representation of a limbs array: a raw pointer to a mutable unsigned 64 bits integer.
type Limbs = *mut u64;

// Receives a Felt and writes its C representation in the limbs variable, as we can't
// return arrays in C.
//
// Felt uses the montgomery representation internally, so to be able to reconstruct a felt
// in a different call, the representative limbs are the ones written as a result of this call.
fn felt_to_limbs(felt: Felt, limbs: Limbs) {
let representative = felt.representative().limbs;
for i in 0..4 {
Expand All @@ -17,6 +25,8 @@ fn felt_to_limbs(felt: Felt, limbs: Limbs) {
}
}

// Receives a C representation of a limbs array and returns a felt representing
// the same number.
fn limbs_to_felt(limbs: Limbs) -> Felt {
unsafe {
let slice: &mut [u64] = std::slice::from_raw_parts_mut(limbs, 4);
Expand Down

0 comments on commit b69158d

Please sign in to comment.