Skip to content

Commit

Permalink
M31 and CM31 Fields
Browse files Browse the repository at this point in the history
  • Loading branch information
spapinistarkware committed Apr 25, 2024
1 parent b2736e3 commit d91d4b7
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 0 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/cairo-ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Cairo workflow
on:
push:
branches:
- main

pull_request:
types:
- opened
- reopened
- synchronize
- auto_merge_enabled

merge_group:
types:
- checks_requested

jobs:
scarb-test:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./stwo_cairo_verifier
steps:
- uses: actions/checkout@v3
- uses: software-mansion/setup-scarb@v1
with:
scarb-version: "2.6.4"
- run: scarb fmt --check
- run: scarb test
1 change: 1 addition & 0 deletions stwo_cairo_verifier/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
target
6 changes: 6 additions & 0 deletions stwo_cairo_verifier/Scarb.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "stwo_cairo_verifier"
version = "0.1.0"
8 changes: 8 additions & 0 deletions stwo_cairo_verifier/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "stwo_cairo_verifier"
version = "0.1.0"
edition = "2023_11"

# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html

[dependencies]
2 changes: 2 additions & 0 deletions stwo_cairo_verifier/src/fields.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod m31;
pub mod cm31;
83 changes: 83 additions & 0 deletions stwo_cairo_verifier/src/fields/cm31.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use super::m31::{M31, m31};

#[derive(Copy, Drop, Debug, PartialEq, Eq)]
pub struct CM31 {
a: M31,
b: M31,
}

pub impl CM31Add of core::traits::Add<CM31> {
fn add(lhs: CM31, rhs: CM31) -> CM31 {
CM31 { a: lhs.a + rhs.a, b: lhs.b + rhs.b }
}
}
pub impl CM31Sub of core::traits::Sub<CM31> {
fn sub(lhs: CM31, rhs: CM31) -> CM31 {
CM31 { a: lhs.a - rhs.a, b: lhs.b - rhs.b }
}
}
pub impl CM31Mul of core::traits::Mul<CM31> {
fn mul(lhs: CM31, rhs: CM31) -> CM31 {
CM31 { a: lhs.a * rhs.a - lhs.b * rhs.b, b: lhs.a * rhs.b + lhs.b * rhs.a }
}
}
pub impl CM31Zero of core::num::traits::Zero<CM31> {
fn zero() -> CM31 {
cm31(0, 0)
}
fn is_zero(self: @CM31) -> bool {
(*self).a.is_zero() && (*self).b.is_zero()
}
fn is_non_zero(self: @CM31) -> bool {
(*self).a.is_non_zero() || (*self).b.is_non_zero()
}
}
pub impl CM31One of core::num::traits::One<CM31> {
fn one() -> CM31 {
cm31(1, 0)
}
fn is_one(self: @CM31) -> bool {
(*self).a.is_one() && (*self).b.is_zero()
}
fn is_non_one(self: @CM31) -> bool {
(*self).a.is_non_one() || (*self).b.is_non_zero()
}
}
pub impl M31IntoCM31 of core::traits::Into<M31, CM31> {
fn into(self: M31) -> CM31 {
CM31 { a: self, b: m31(0) }
}
}
pub impl CM31Neg of Neg<CM31> {
fn neg(a: CM31) -> CM31 {
CM31 { a: -a.a, b: -a.b }
}
}

pub fn cm31(a: u32, b: u32) -> CM31 {
CM31 { a: m31(a), b: m31(b) }
}


#[cfg(test)]
mod tests {
use super::{cm31};
use super::super::m31::{m31, P};

#[test]
fn test_cm31() {
let cm0 = cm31(1, 2);
let cm1 = cm31(4, 5);
let m = m31(8);
let cm = cm31(8, 0);
let cm0_x_cm1 = cm31(P - 6, 13);

assert_eq!(cm0 + cm1, cm31(5, 7));
assert_eq!(cm1 + m.into(), cm1 + cm);
assert_eq!(cm0 * cm1, cm0_x_cm1);
assert_eq!(cm1 * m.into(), cm1 * cm);
assert_eq!(-cm0, cm31(P - 1, P - 2));
assert_eq!(cm0 - cm1, cm31(P - 3, P - 3));
assert_eq!(cm1 - m.into(), cm1 - cm);
}
}
93 changes: 93 additions & 0 deletions stwo_cairo_verifier/src/fields/m31.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use core::option::OptionTrait;
use core::traits::TryInto;
use core::result::ResultTrait;

pub const P: u32 = 0x7fffffff;
const P32NZ: NonZero<u32> = 0x7fffffff;
const P64NZ: NonZero<u64> = 0x7fffffff;

#[derive(Copy, Drop, Debug, PartialEq, Eq)]
pub struct M31 {
inner: u32
}

#[generate_trait]
pub impl M31Impl of M31Trait {
fn reduce_u32(val: u32) -> M31 {
let (_, res) = core::integer::u32_safe_divmod(val, P32NZ);
M31 { inner: res.try_into().unwrap() }
}

fn reduce_u64(val: u64) -> M31 {
let (_, res) = core::integer::u64_safe_divmod(val, P64NZ);
M31 { inner: res.try_into().unwrap() }
}
}
pub impl M31Add of core::traits::Add<M31> {
fn add(lhs: M31, rhs: M31) -> M31 {
let res = lhs.inner + rhs.inner;
let res = core::integer::u32_overflowing_sub(res, P).unwrap_or(res);
M31 { inner: res }
}
}
pub impl M31Sub of core::traits::Sub<M31> {
fn sub(lhs: M31, rhs: M31) -> M31 {
lhs + (-rhs)
}
}
pub impl M31Mul of core::traits::Mul<M31> {
fn mul(lhs: M31, rhs: M31) -> M31 {
M31Impl::reduce_u64(core::integer::u32_wide_mul(lhs.inner, rhs.inner))
}
}
pub impl M31Zero of core::num::traits::Zero<M31> {
fn zero() -> M31 {
M31 { inner: 0 }
}
fn is_zero(self: @M31) -> bool {
*self.inner == 0
}
fn is_non_zero(self: @M31) -> bool {
*self.inner != 0
}
}
pub impl M31One of core::num::traits::One<M31> {
fn one() -> M31 {
M31 { inner: 1 }
}
fn is_one(self: @M31) -> bool {
*self.inner == 1
}
fn is_non_one(self: @M31) -> bool {
*self.inner != 1
}
}
pub impl M31Neg of Neg<M31> {
fn neg(a: M31) -> M31 {
if a.inner == 0 {
M31 { inner: 0 }
} else {
M31 { inner: P - a.inner }
}
}
}

pub fn m31(val: u32) -> M31 {
M31Impl::reduce_u32(val)
}

#[cfg(test)]
mod tests {
use super::{m31, P};

#[test]
fn test_m31() {
assert_eq!(m31(P), m31(0));
assert_eq!(m31(P + 1), m31(1));
assert_eq!(m31(1) + m31(2), m31(3));
assert_eq!(m31(3) - m31(2), m31(1));
assert_eq!(m31(P - 1) + m31(1), m31(0));
assert_eq!(m31(0) - m31(1), m31(P - 1));
assert_eq!(m31(0) - m31(P - 1), m31(1));
}
}
3 changes: 3 additions & 0 deletions stwo_cairo_verifier/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod fields;

fn main() {}

0 comments on commit d91d4b7

Please sign in to comment.