Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bitwise math #107

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion aiken.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "aiken-lang/stdlib"
version = "main"
compiler = "v1.1.11"
compiler = "v1.1.12"
plutus = "v3"
description = "The Aiken Standard Library"

Expand Down
134 changes: 134 additions & 0 deletions lib/aiken/crypto/bitwise.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use aiken/builtin

pub opaque type State<t> {
inner: Int,
}

pub const zero = State { inner: 0 }

pub const one = State { inner: 1 }

pub fn add_bits(field: Int, big_endian: Bool) {
fn(state: State<t>, bytes: ByteArray) -> State<t> {
builtin.bytearray_to_integer(big_endian, bytes)
|> builtin.add_integer(state.inner)
|> builtin.mod_integer(field)
|> State
}
}

pub fn add_int(field: Int) {
fn(state: State<t>, int: Int) -> State<t> {
state.inner + int
|> builtin.mod_integer(field)
|> State
}
}

pub fn add_state(field: Int) {
fn(state: State<t>, other: State<t>) -> State<t> {
state.inner + other.inner
|> builtin.mod_integer(field)
|> State
}
}

pub fn sub_bits(field: Int, big_endian: Bool) {
fn(state: State<t>, bytes: ByteArray) -> State<t> {
builtin.bytearray_to_integer(big_endian, bytes)
|> builtin.subtract_integer(state.inner)
|> builtin.mod_integer(field)
|> State
}
}

pub fn sub_int(field: Int) {
fn(state: State<t>, int: Int) -> State<t> {
state.inner - int
|> builtin.mod_integer(field)
|> State
}
}

pub fn sub_state(field: Int) {
fn(state: State<t>, other: State<t>) -> State<t> {
state.inner - other.inner
|> builtin.mod_integer(field)
|> State
}
}

pub fn mul_bits(field: Int, big_endian: Bool) {
fn(state: State<t>, bytes: ByteArray) -> State<t> {
builtin.bytearray_to_integer(big_endian, bytes)
|> builtin.multiply_integer(state.inner)
|> builtin.mod_integer(field)
|> State
}
}

pub fn mul_int(field: Int) {
fn(state: State<t>, int: Int) -> State<t> {
state.inner * int
|> builtin.mod_integer(field)
|> State
}
}

pub fn mul_state(field: Int) {
fn(state: State<t>, other: State<t>) -> State<t> {
state.inner * other.inner
|> builtin.mod_integer(field)
|> State
}
}

pub fn scale(
self: State<t>,
e: Int,
mul: fn(State<t>, State<t>) -> State<t>,
) -> State<t> {
if e < 0 {
zero
} else if e == 0 {
one
} else if e % 2 == 0 {
scale(mul(self, self), e / 2, mul)
} else {
mul(self, scale(mul(self, self), ( e - 1 ) / 2, mul))
}
}

/// A faster version of `scale` for the case where the exponent is a power of two.
/// That is, the exponent `e = 2^k` for some non-negative integer `k`. Which is used alot in zk-SNARKs.
pub fn scale2(self: State<t>, k: Int, mul: fn(State<t>, State<t>) -> State<t>) {
if k < 0 {
zero
} else {
do_scale2(self, k, mul)
}
}

fn do_scale2(self: State<t>, k: Int, mul) -> State<t> {
if k == 0 {
self
} else {
do_scale2(mul(self, self), k - 1, mul)
}
}

pub fn neg(field: Int) {
fn(state: State<t>) -> State<t> {
( field - state.inner ) % field
|> State
}
}

pub fn to_int(state: State<t>) -> Int {
state.inner
}

pub fn from_int(int: Int, field: Int) -> State<t> {
int % field
|> State
}
5 changes: 3 additions & 2 deletions lib/aiken/crypto/bls12_381/g1.ak
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//// This module ensures that all operations respect the properties of the BLS12-381 curve and the mathematical structure of the G1 group.

use aiken/builtin
use aiken/crypto/bitwise.{State}
use aiken/crypto/bls12_381/scalar.{Scalar}

/// The compressed generator of the G1 group of the BLS12-381 curve.
Expand Down Expand Up @@ -95,12 +96,12 @@ test sub_1() {

/// Exponentiates a point in the G1 group with a `scalar`.
/// This operation is equivalent to the repeated addition of the point with itself `e` times.
pub fn scale(point, e: Scalar) {
pub fn scale(point, e: State<Scalar>) {
builtin.bls12_381_g1_scalar_mul(scalar.to_int(e), point)
}

test scale_1() {
expect Some(x) = scalar.new(2)
let x = scalar.from_int(2)
builtin.bls12_381_g1_add(generator, generator) == scale(generator, x)
}

Expand Down
5 changes: 3 additions & 2 deletions lib/aiken/crypto/bls12_381/g2.ak
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//// This module ensures that all operations respect the properties of the BLS12-381 curve and the mathematical structure of the G2 group.

use aiken/builtin
use aiken/crypto/bitwise.{State}
use aiken/crypto/bls12_381/scalar.{Scalar}

/// The compressed generator of the G2 group of the BLS12-381 curve.
Expand Down Expand Up @@ -104,12 +105,12 @@ test sub_1() {

/// Exponentiates a point in the G2 group with a `scalar`.
/// This operation is equivalent to the repeated addition of the point with itself `e` times.
pub fn scale(point, e: Scalar) {
pub fn scale(point, e: State<Scalar>) {
builtin.bls12_381_g2_scalar_mul(scalar.to_int(e), point)
}

test scale_1() {
expect Some(x) = scalar.new(2)
let x = scalar.from_int(2)
builtin.bls12_381_g2_add(generator, generator) == scale(generator, x)
}

Expand Down
Loading