Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelogs/unreleased/1304-dark64
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add implementation of big integer arithmetic to stdlib
110 changes: 110 additions & 0 deletions zokrates_stdlib/stdlib/algebra/biginteger.zok
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
from "field" import FIELD_SIZE_IN_BITS;
import "utils/pack/bool/unpack_unchecked" as unpack;
import "utils/pack/bool/pack" as pack;

struct BigInteger<N> {
field[N] limbs;
}

// Construct a big integer from `N` limbs
def bigint_from_limbs<N, M>(field[N] values) -> BigInteger<M> {
assert(M >= N, "invalid number of limbs");
return BigInteger { limbs: [...values, ...[0; M-N]] };
}

// Expand big integer from `N` limbs to `M`
def bigint_expand<N, M>(BigInteger<N> input) -> BigInteger<M> {
return bigint_from_limbs(input.limbs);
}

// Truncate big integer from `N` limbs to `M`
def bigint_truncate<N, M>(BigInteger<N> input) -> BigInteger<M> {
assert(M <= N, "invalid number of limbs");
return BigInteger { limbs: input.limbs[..M] };
}

// Big integer addition
def bigint_add<N, M>(BigInteger<N> a, BigInteger<N> b) -> BigInteger<N> {
assert(M < FIELD_SIZE_IN_BITS - 1);
BigInteger<N> mut c = bigint_from_limbs([0; N]);
field mut carry = 0;
for u32 i in 0..N {
field sum = a.limbs[i] + b.limbs[i] + carry;
bool[M + 1] bits = unpack(sum);
carry = bits[0] ? 1 : 0;
c.limbs[i] = sum - carry * (1 << M);
}
return c;
}

// Big integer subtraction (assumes a >= b)
def bigint_sub<N, M>(BigInteger<N> a, BigInteger<N> b) -> BigInteger<N> {
assert(M < FIELD_SIZE_IN_BITS - 1);
BigInteger<N> mut c = bigint_from_limbs([0; N]);
field mut borrow = 0;
for u32 i in 0..N {
c.limbs[i] = borrow * (1 << M) + (a.limbs[i] - b.limbs[i]);
bool[M + 1] bits = unpack(a.limbs[i] + (1 << M) - b.limbs[i]);
borrow = bits[0] ? 0 : 1;
}
return c;
}

// Right shift by `n` limbs
def bigint_rshift_limb<N>(BigInteger<N> mut a, u32 n) -> BigInteger<N> {
assert(n < N);
for u32 i in 0..N-n {
a.limbs[i] = a.limbs[i + n];
}
for u32 i in N-n..N {
a.limbs[i] = 0;
}
return a;
}

// Left shift by `n` limbs
def bigint_lshift_limb<N>(BigInteger<N> mut a, u32 n) -> BigInteger<N> {
assert(n < N);
for u32 i in 0..N-n {
u32 j = N - i - 1;
a.limbs[j] = a.limbs[j - n];
}
for u32 i in 0..n {
a.limbs[i] = 0;
}
return a;
}

// Big integer multiplication
def bigint_mul<N, M>(BigInteger<N> a, BigInteger<N> b) -> BigInteger<N> {
assert(M <= FIELD_SIZE_IN_BITS / 2);
BigInteger<N> mut c = bigint_from_limbs([0; N]);
for u32 i in 0..N {
BigInteger<N> mut row = bigint_from_limbs([0; N]);
for u32 j in 0..N {
field acc = a.limbs[i] * b.limbs[j];
bool[2*M] bits = unpack(acc);
field lo = pack(bits[M..]);
field hi = pack(bits[..M]);
BigInteger<N> mut tmp = bigint_from_limbs([lo, hi]);
row = i + j < N ? bigint_add::<N, M>(bigint_lshift_limb(tmp, i + j), row) : row;
}
c = bigint_add::<N, M>(c, row);
}
return c;
}

// Check equality of two big integers
def bigint_eq<N>(BigInteger<N> a, BigInteger<N> b) -> bool {
bool mut eq = true;
for u32 i in 0..N {
eq = eq && (a.limbs[i] == b.limbs[i]);
}
return eq;
}

// Check if a big integer is equal to 0
def bigint_is_zero<N>(BigInteger<N> a) -> bool {
BigInteger<N> zero = bigint_from_limbs([0; N]);
return bigint_eq(a, zero);
}
36 changes: 36 additions & 0 deletions zokrates_stdlib/tests/tests/algebra/biginteger/bigint_add.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"max_constraint_count": 22,
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": [{ "limbs": ["2", "2"] }, { "limbs": ["2", "0"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["4", "2"] }
}
}
},
{
"input": {
"values": [{ "limbs": ["255", "0"] }, { "limbs": ["1", "0"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["0", "1"] }
}
}
},
{
"input": {
"values": [{ "limbs": ["129", "1"] }, { "limbs": ["128", "1"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["1", "3"] }
}
}
}
]
}
6 changes: 6 additions & 0 deletions zokrates_stdlib/tests/tests/algebra/biginteger/bigint_add.zok
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from "algebra/biginteger" import BigInteger, bigint_add;

def main(BigInteger<2> a, BigInteger<2> b) -> BigInteger<2> {
BigInteger<2> c = bigint_add::<2, 8>(a, b);
return c;
}
36 changes: 36 additions & 0 deletions zokrates_stdlib/tests/tests/algebra/biginteger/bigint_eq.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"max_constraint_count": 6,
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": [{ "limbs": ["2", "2"] }, { "limbs": ["2", "0"] }]
},
"output": {
"Ok": {
"value": false
}
}
},
{
"input": {
"values": [{ "limbs": ["2", "2"] }, { "limbs": ["0", "2"] }]
},
"output": {
"Ok": {
"value": false
}
}
},
{
"input": {
"values": [{ "limbs": ["2", "2"] }, { "limbs": ["2", "2"] }]
},
"output": {
"Ok": {
"value": true
}
}
}
]
}
5 changes: 5 additions & 0 deletions zokrates_stdlib/tests/tests/algebra/biginteger/bigint_eq.zok
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from "algebra/biginteger" import BigInteger, bigint_eq;

def main(BigInteger<2> a, BigInteger<2> b) -> bool {
return bigint_eq(a, b);
}
16 changes: 16 additions & 0 deletions zokrates_stdlib/tests/tests/algebra/biginteger/bigint_expand.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"max_constraint_count": 4,
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": [{ "limbs": ["2", "2"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["2", "2", "0", "0"] }
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from "algebra/biginteger" import BigInteger, bigint_expand;

def main(BigInteger<2> a) -> BigInteger<4> {
BigInteger<4> b = bigint_expand(a);
return b;
}
36 changes: 36 additions & 0 deletions zokrates_stdlib/tests/tests/algebra/biginteger/bigint_is_zero.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"max_constraint_count": 6,
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": [{ "limbs": ["0", "2"] }]
},
"output": {
"Ok": {
"value": false
}
}
},
{
"input": {
"values": [{ "limbs": ["2", "0"] }]
},
"output": {
"Ok": {
"value": false
}
}
},
{
"input": {
"values": [{ "limbs": ["0", "0"] }]
},
"output": {
"Ok": {
"value": true
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from "algebra/biginteger" import BigInteger, bigint_is_zero;

def main(BigInteger<2> a) -> bool {
return bigint_is_zero(a);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"max_constraint_count": 22,
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": [{ "limbs": ["2", "2"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["0", "2"] }
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from "algebra/biginteger" import BigInteger, bigint_lshift_limb;

def main(BigInteger<2> a) -> BigInteger<2> {
BigInteger<2> c = bigint_lshift_limb(a, 1);
return c;
}
46 changes: 46 additions & 0 deletions zokrates_stdlib/tests/tests/algebra/biginteger/bigint_mul.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"max_constraint_count": 506,
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": [{ "limbs": ["2", "2"] }, { "limbs": ["2", "0"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["4", "4"] }
}
}
},
{
"input": {
"values": [{ "limbs": ["128", "0"] }, { "limbs": ["0", "2"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["0", "256"] }
}
}
},
{
"input": {
"values": [{ "limbs": ["4294967295", "0"] }, { "limbs": ["2", "0"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["4294967294", "1"] }
}
}
},
{
"input": {
"values": [{ "limbs": ["256", "512"] }, { "limbs": ["512", "0"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["131072", "262144"] }
}
}
}
]
}
6 changes: 6 additions & 0 deletions zokrates_stdlib/tests/tests/algebra/biginteger/bigint_mul.zok
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from "algebra/biginteger" import BigInteger, bigint_mul;

def main(BigInteger<2> a, BigInteger<2> b) -> BigInteger<2> {
BigInteger<2> c = bigint_mul::<2, 32>(a, b);
return c;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"max_constraint_count": 22,
"curves": ["Bn128"],
"tests": [
{
"input": {
"values": [{ "limbs": ["2", "2"] }]
},
"output": {
"Ok": {
"value": { "limbs": ["2", "0"] }
}
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from "algebra/biginteger" import BigInteger, bigint_rshift_limb;

def main(BigInteger<2> a) -> BigInteger<2> {
BigInteger<2> c = bigint_rshift_limb(a, 1);
return c;
}
Loading