From 491644fa5d2fc0324f8d97cd2a197c9594f7a63c Mon Sep 17 00:00:00 2001 From: logicalmechanism Date: Tue, 18 Feb 2025 18:48:07 -0800 Subject: [PATCH 01/16] its a start, would need a lot of work and use of fuzzy wuzzy --- lib/aiken/math/bitwise.ak | 135 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 lib/aiken/math/bitwise.ak diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak new file mode 100644 index 0000000..8f0d19c --- /dev/null +++ b/lib/aiken/math/bitwise.ak @@ -0,0 +1,135 @@ +use aiken/builtin + +pub fn add(a: ByteArray, b: ByteArray) -> ByteArray { + if builtin.count_set_bits(b) == 0 { + a + } else { + let carry: ByteArray = + builtin.and_bytearray(True, a, b) |> builtin.shift_bytearray(1) + let sum_without_carry: ByteArray = builtin.xor_bytearray(True, a, b) + add(sum_without_carry, carry) + } +} + +test one_plus_one() { + let one = builtin.integer_to_bytearray(True, 0, 1) + let two = builtin.integer_to_bytearray(True, 0, 2) + add(one, one) == two +} + +test add_to_zero() { + // add(#"00", #"acab") == #"acab" + add(#"acab", #"00") == #"acab" +} + +test mix_addition() { + let a = builtin.integer_to_bytearray(True, 0, 12) + let b = builtin.integer_to_bytearray(True, 0, 34151) + add(a, b) == add(b, a) +} + +test small_addition() { + let a = builtin.integer_to_bytearray(True, 0, 31) + let b = builtin.integer_to_bytearray(True, 0, 51) + let result = builtin.integer_to_bytearray(True, 0, 82) + add(a, b) == result +} + +test medium_addition() { + let a = builtin.integer_to_bytearray(True, 0, 1313) + let b = builtin.integer_to_bytearray(True, 0, 1514) + let result = builtin.integer_to_bytearray(True, 0, 2827) + add(a, b) == result +} + +test large_addition() { + let a = builtin.integer_to_bytearray(True, 0, 123456789) + let b = builtin.integer_to_bytearray(True, 0, 987654321) + let result = builtin.integer_to_bytearray(True, 0, 1111111110) + add(a, b) == result +} + +test xlarge_addition() { + let a = + builtin.integer_to_bytearray(True, 0, 123456789123456789123456789123456789) + let b = + builtin.integer_to_bytearray(True, 0, 987654321987654321987654321987654321) + let result = + builtin.integer_to_bytearray(True, 0, 1111111111111111111111111111111111110) + add(a, b) == result +} + +pub fn subtract(a: ByteArray, b: ByteArray) -> ByteArray { + if builtin.count_set_bits(b) == 0 { + a + } else { + let borrow: ByteArray = + builtin.and_bytearray(True, builtin.complement_bytearray(a), b) + |> builtin.shift_bytearray(1) + let diff_without_borrow: ByteArray = builtin.xor_bytearray(True, a, b) + subtract(diff_without_borrow, borrow) + } +} + +test one_minus_one() { + let one = builtin.integer_to_bytearray(True, 0, 1) + subtract(one, one) == #"00" +} + +test small_subtraction1() { + let a = builtin.integer_to_bytearray(True, 0, 31) + let b = builtin.integer_to_bytearray(True, 0, 51) + let result = builtin.integer_to_bytearray(True, 0, 256 - 20) + subtract(a, b) == result +} + +test small_subtraction2() { + let a = builtin.integer_to_bytearray(True, 0, 31) + let b = builtin.integer_to_bytearray(True, 0, 51) + let result = builtin.integer_to_bytearray(True, 0, 20) + subtract(b, a) == result +} + +pub fn multiply(a: ByteArray, b: ByteArray) -> ByteArray { + do_multiply(a, b, #"00") +} + +pub fn do_multiply(a: ByteArray, b: ByteArray, acc: ByteArray) -> ByteArray { + trace acc + if builtin.count_set_bits(b) == 0 { + acc + } else { + // Check the least significant bit of b. + // If it is set, then add the current value of a to the accumulator. + let bit_set = builtin.and_bytearray(True, b, #"01") + let new_acc = + if builtin.count_set_bits(bit_set) > 0 { + add(a, acc) + } else { + acc + } + // trace new_acc + // Shift a left by 1 (multiply a by 2). + let new_a = builtin.shift_bytearray(a, 1) + // trace new_a + // Shift b right by 1 (divide b by 2). + let new_b = builtin.shift_bytearray(b, -1) + + // trace new_b + do_multiply(new_a, new_b, new_acc) + } +} + +test small_multiply() { + let a = builtin.integer_to_bytearray(True, 0, 2) + let b = builtin.integer_to_bytearray(True, 0, 3) + let result = builtin.integer_to_bytearray(True, 0, 6) + multiply(a, b) == result +} + +test medium_multiply() { + let a = builtin.integer_to_bytearray(True, 0, 21) + let b = builtin.integer_to_bytearray(True, 0, 31) + let result = builtin.integer_to_bytearray(True, 0, 651) + multiply(a, b) == result +} From f17aeff9e0be60f6cba3ac20743edd8c996d0280 Mon Sep 17 00:00:00 2001 From: logicalmechanism Date: Tue, 18 Feb 2025 20:19:33 -0800 Subject: [PATCH 02/16] good start --- lib/aiken/math/bitwise.ak | 128 ++------------------------------ lib/aiken/math/bitwise.tests.ak | 30 ++++++++ 2 files changed, 35 insertions(+), 123 deletions(-) create mode 100644 lib/aiken/math/bitwise.tests.ak diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak index 8f0d19c..7bd84bf 100644 --- a/lib/aiken/math/bitwise.ak +++ b/lib/aiken/math/bitwise.ak @@ -1,5 +1,10 @@ use aiken/builtin +/// Adds two ByteArrays together using bitwise operations. +/// +/// ```aiken +/// bitwise.add(#"00acab", #"00cafe") == #"0177A9" +/// `` pub fn add(a: ByteArray, b: ByteArray) -> ByteArray { if builtin.count_set_bits(b) == 0 { a @@ -10,126 +15,3 @@ pub fn add(a: ByteArray, b: ByteArray) -> ByteArray { add(sum_without_carry, carry) } } - -test one_plus_one() { - let one = builtin.integer_to_bytearray(True, 0, 1) - let two = builtin.integer_to_bytearray(True, 0, 2) - add(one, one) == two -} - -test add_to_zero() { - // add(#"00", #"acab") == #"acab" - add(#"acab", #"00") == #"acab" -} - -test mix_addition() { - let a = builtin.integer_to_bytearray(True, 0, 12) - let b = builtin.integer_to_bytearray(True, 0, 34151) - add(a, b) == add(b, a) -} - -test small_addition() { - let a = builtin.integer_to_bytearray(True, 0, 31) - let b = builtin.integer_to_bytearray(True, 0, 51) - let result = builtin.integer_to_bytearray(True, 0, 82) - add(a, b) == result -} - -test medium_addition() { - let a = builtin.integer_to_bytearray(True, 0, 1313) - let b = builtin.integer_to_bytearray(True, 0, 1514) - let result = builtin.integer_to_bytearray(True, 0, 2827) - add(a, b) == result -} - -test large_addition() { - let a = builtin.integer_to_bytearray(True, 0, 123456789) - let b = builtin.integer_to_bytearray(True, 0, 987654321) - let result = builtin.integer_to_bytearray(True, 0, 1111111110) - add(a, b) == result -} - -test xlarge_addition() { - let a = - builtin.integer_to_bytearray(True, 0, 123456789123456789123456789123456789) - let b = - builtin.integer_to_bytearray(True, 0, 987654321987654321987654321987654321) - let result = - builtin.integer_to_bytearray(True, 0, 1111111111111111111111111111111111110) - add(a, b) == result -} - -pub fn subtract(a: ByteArray, b: ByteArray) -> ByteArray { - if builtin.count_set_bits(b) == 0 { - a - } else { - let borrow: ByteArray = - builtin.and_bytearray(True, builtin.complement_bytearray(a), b) - |> builtin.shift_bytearray(1) - let diff_without_borrow: ByteArray = builtin.xor_bytearray(True, a, b) - subtract(diff_without_borrow, borrow) - } -} - -test one_minus_one() { - let one = builtin.integer_to_bytearray(True, 0, 1) - subtract(one, one) == #"00" -} - -test small_subtraction1() { - let a = builtin.integer_to_bytearray(True, 0, 31) - let b = builtin.integer_to_bytearray(True, 0, 51) - let result = builtin.integer_to_bytearray(True, 0, 256 - 20) - subtract(a, b) == result -} - -test small_subtraction2() { - let a = builtin.integer_to_bytearray(True, 0, 31) - let b = builtin.integer_to_bytearray(True, 0, 51) - let result = builtin.integer_to_bytearray(True, 0, 20) - subtract(b, a) == result -} - -pub fn multiply(a: ByteArray, b: ByteArray) -> ByteArray { - do_multiply(a, b, #"00") -} - -pub fn do_multiply(a: ByteArray, b: ByteArray, acc: ByteArray) -> ByteArray { - trace acc - if builtin.count_set_bits(b) == 0 { - acc - } else { - // Check the least significant bit of b. - // If it is set, then add the current value of a to the accumulator. - let bit_set = builtin.and_bytearray(True, b, #"01") - let new_acc = - if builtin.count_set_bits(bit_set) > 0 { - add(a, acc) - } else { - acc - } - // trace new_acc - // Shift a left by 1 (multiply a by 2). - let new_a = builtin.shift_bytearray(a, 1) - // trace new_a - // Shift b right by 1 (divide b by 2). - let new_b = builtin.shift_bytearray(b, -1) - - // trace new_b - do_multiply(new_a, new_b, new_acc) - } -} - -test small_multiply() { - let a = builtin.integer_to_bytearray(True, 0, 2) - let b = builtin.integer_to_bytearray(True, 0, 3) - let result = builtin.integer_to_bytearray(True, 0, 6) - multiply(a, b) == result -} - -test medium_multiply() { - let a = builtin.integer_to_bytearray(True, 0, 21) - let b = builtin.integer_to_bytearray(True, 0, 31) - let result = builtin.integer_to_bytearray(True, 0, 651) - multiply(a, b) == result -} diff --git a/lib/aiken/math/bitwise.tests.ak b/lib/aiken/math/bitwise.tests.ak new file mode 100644 index 0000000..209b6fc --- /dev/null +++ b/lib/aiken/math/bitwise.tests.ak @@ -0,0 +1,30 @@ +use aiken/builtin +use aiken/math/bitwise.{add} + +test one_plus_one() { + let one = builtin.integer_to_bytearray(True, 0, 1) + let two = builtin.integer_to_bytearray(True, 0, 2) + add(one, one) == two +} + +test emptiness_is_empty() { + add(#"", #"") == #"" +} + +test not_equal_length_does_not_work() fail { + add(#"00", #"acab") == #"acab" +} + +test communitive() { + add(#"acab", #"0000") == add(#"0000", #"acab") +} + +test associativity() { + ( add(#"0101", #"0202") |> add(#"0303") ) == ( + add(#"0202", #"0303") |> add(#"0101") + ) +} + +test identity() { + add(#"00", #"01") == #"01" +} From 9211756c9acc14ff54ec1f5da65087d77c5168f4 Mon Sep 17 00:00:00 2001 From: logicalmechanism Date: Tue, 18 Feb 2025 20:59:19 -0800 Subject: [PATCH 03/16] adding a pad addition function to prepad bytearrays if required --- lib/aiken/math/bitwise.ak | 36 ++++++++++++++++++++++++-- lib/aiken/math/bitwise.tests.ak | 45 ++++++++++++++++++++++++++++----- 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak index 7bd84bf..926e998 100644 --- a/lib/aiken/math/bitwise.ak +++ b/lib/aiken/math/bitwise.ak @@ -1,10 +1,42 @@ use aiken/builtin -/// Adds two ByteArrays together using bitwise operations. +/// Addition will at most add a single byte to a bytearray. This will prepad the +/// bytearrays to the correct length for addition and it will correct for mismatched +/// lengths. +/// +/// ```aiken +/// bitwise.pad_addition(#"acab", #"cafe") == (#"00acab", #"00cafe") +/// ``` +pub fn pad_addition(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { + let length_a: Int = builtin.length_of_bytearray(a) + let length_b: Int = builtin.length_of_bytearray(b) + if length_a >= length_b { + let diff: Int = length_a - length_b + ( + builtin.cons_bytearray(0, a), + builtin.append_bytearray(builtin.replicate_byte(diff + 1, 0), b), + ) + } else { + let diff: Int = length_b - length_a + ( + builtin.append_bytearray(builtin.replicate_byte(diff + 1, 0), a), + builtin.cons_bytearray(0, b), + ) + } +} + +/// Add two ByteArrays together using bitwise operations. The function assumes +/// fixed-width (modular) arithmetic. +/// +/// -- pad inputs for arbitrary precision /// /// ```aiken /// bitwise.add(#"00acab", #"00cafe") == #"0177A9" -/// `` +/// ``` +/// +/// ```aiken +/// bitwise.add(#"acab", #"cafe") == #"77A9" +/// ``` pub fn add(a: ByteArray, b: ByteArray) -> ByteArray { if builtin.count_set_bits(b) == 0 { a diff --git a/lib/aiken/math/bitwise.tests.ak b/lib/aiken/math/bitwise.tests.ak index 209b6fc..ce807a7 100644 --- a/lib/aiken/math/bitwise.tests.ak +++ b/lib/aiken/math/bitwise.tests.ak @@ -1,10 +1,43 @@ -use aiken/builtin -use aiken/math/bitwise.{add} +use aiken/math/bitwise.{add, pad_addition} -test one_plus_one() { - let one = builtin.integer_to_bytearray(True, 0, 1) - let two = builtin.integer_to_bytearray(True, 0, 2) - add(one, one) == two +test equal_pad_addition() { + let a: ByteArray = #"acab" + let b: ByteArray = #"cafe" + let (new_a, new_b) = pad_addition(a, b) + and { + new_a == #"00acab", + new_b == #"00cafe", + } +} + +test unequal_pad_addition1() { + let a: ByteArray = #"acabbeefface" + let b: ByteArray = #"cafe" + let (new_a, new_b) = pad_addition(a, b) + and { + new_a == #"00acabbeefface", + new_b == #"0000000000cafe", + } +} + +test unequal_pad_addition2() { + let b: ByteArray = #"acabbeefface" + let a: ByteArray = #"cafe" + let (new_a, new_b) = pad_addition(a, b) + and { + new_a == #"0000000000cafe", + new_b == #"00acabbeefface", + } +} + +test pad_for_addition() { + let b: ByteArray = #"acab" + let a: ByteArray = #"cafe" + let (new_a, new_b) = pad_addition(a, b) + and { + add(a, b) == #"77a9", + add(new_a, new_b) == #"0177a9", + } } test emptiness_is_empty() { From 233f9a039403fb5038434044d255b81cfabe37ae Mon Sep 17 00:00:00 2001 From: logicalmechanism Date: Tue, 18 Feb 2025 21:07:28 -0800 Subject: [PATCH 04/16] adding comments and adjusting naming --- lib/aiken/math/bitwise.ak | 11 +++++++---- lib/aiken/math/bitwise.tests.ak | 18 +++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak index 926e998..f5c145b 100644 --- a/lib/aiken/math/bitwise.ak +++ b/lib/aiken/math/bitwise.ak @@ -5,9 +5,9 @@ use aiken/builtin /// lengths. /// /// ```aiken -/// bitwise.pad_addition(#"acab", #"cafe") == (#"00acab", #"00cafe") +/// bitwise.pad_for_addition(#"acab", #"cafe") == (#"00acab", #"00cafe") /// ``` -pub fn pad_addition(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { +pub fn pad_for_addition(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { let length_a: Int = builtin.length_of_bytearray(a) let length_b: Int = builtin.length_of_bytearray(b) if length_a >= length_b { @@ -25,8 +25,9 @@ pub fn pad_addition(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { } } -/// Add two ByteArrays together using bitwise operations. The function assumes -/// fixed-width (modular) arithmetic. +/// Add two ByteArrays together, a + b, using bitwise operations. The function +/// assumes fixed-width (modular) arithmetic. If arbitrary precision is required +/// use `pad_for_addition`. /// /// -- pad inputs for arbitrary precision /// @@ -34,6 +35,8 @@ pub fn pad_addition(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { /// bitwise.add(#"00acab", #"00cafe") == #"0177A9" /// ``` /// +/// -- otherwise +/// /// ```aiken /// bitwise.add(#"acab", #"cafe") == #"77A9" /// ``` diff --git a/lib/aiken/math/bitwise.tests.ak b/lib/aiken/math/bitwise.tests.ak index ce807a7..675d3fe 100644 --- a/lib/aiken/math/bitwise.tests.ak +++ b/lib/aiken/math/bitwise.tests.ak @@ -1,39 +1,39 @@ -use aiken/math/bitwise.{add, pad_addition} +use aiken/math/bitwise.{add, pad_for_addition} -test equal_pad_addition() { +test equal_pad_for_addition() { let a: ByteArray = #"acab" let b: ByteArray = #"cafe" - let (new_a, new_b) = pad_addition(a, b) + let (new_a, new_b) = pad_for_addition(a, b) and { new_a == #"00acab", new_b == #"00cafe", } } -test unequal_pad_addition1() { +test unequal_pad_for_addition1() { let a: ByteArray = #"acabbeefface" let b: ByteArray = #"cafe" - let (new_a, new_b) = pad_addition(a, b) + let (new_a, new_b) = pad_for_addition(a, b) and { new_a == #"00acabbeefface", new_b == #"0000000000cafe", } } -test unequal_pad_addition2() { +test unequal_pad_for_addition2() { let b: ByteArray = #"acabbeefface" let a: ByteArray = #"cafe" - let (new_a, new_b) = pad_addition(a, b) + let (new_a, new_b) = pad_for_addition(a, b) and { new_a == #"0000000000cafe", new_b == #"00acabbeefface", } } -test pad_for_addition() { +test pad_for_addition_works() { let b: ByteArray = #"acab" let a: ByteArray = #"cafe" - let (new_a, new_b) = pad_addition(a, b) + let (new_a, new_b) = pad_for_addition(a, b) and { add(a, b) == #"77a9", add(new_a, new_b) == #"0177a9", From 38d90452521a578a9c537e8562461662cad37e43 Mon Sep 17 00:00:00 2001 From: logicalmechanism Date: Tue, 18 Feb 2025 21:18:08 -0800 Subject: [PATCH 05/16] subtraction using the borrow method instead of 2s --- lib/aiken/math/bitwise.ak | 19 +++++++++++++++++- lib/aiken/math/bitwise.tests.ak | 34 ++++++++++++++++++++++++++------- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak index f5c145b..8861d39 100644 --- a/lib/aiken/math/bitwise.ak +++ b/lib/aiken/math/bitwise.ak @@ -25,7 +25,7 @@ pub fn pad_for_addition(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { } } -/// Add two ByteArrays together, a + b, using bitwise operations. The function +/// Add two ByteArrays, a + b, using bitwise operations. The function /// assumes fixed-width (modular) arithmetic. If arbitrary precision is required /// use `pad_for_addition`. /// @@ -50,3 +50,20 @@ pub fn add(a: ByteArray, b: ByteArray) -> ByteArray { add(sum_without_carry, carry) } } + +/// Subtracts two ByteArrays, a - b, using bitwise operations. +/// +/// ```aiken +/// bitwise.subtract(#"77a9", #"cafe") == #"acab" +/// ``` +pub fn subtract(a: ByteArray, b: ByteArray) -> ByteArray { + if builtin.count_set_bits(b) == 0 { + a + } else { + let borrow: ByteArray = + builtin.and_bytearray(True, builtin.complement_bytearray(a), b) + |> builtin.shift_bytearray(1) + let diff_without_borrow: ByteArray = builtin.xor_bytearray(True, a, b) + subtract(diff_without_borrow, borrow) + } +} diff --git a/lib/aiken/math/bitwise.tests.ak b/lib/aiken/math/bitwise.tests.ak index 675d3fe..c742207 100644 --- a/lib/aiken/math/bitwise.tests.ak +++ b/lib/aiken/math/bitwise.tests.ak @@ -1,4 +1,4 @@ -use aiken/math/bitwise.{add, pad_for_addition} +use aiken/math/bitwise.{add, pad_for_addition, subtract} test equal_pad_for_addition() { let a: ByteArray = #"acab" @@ -30,7 +30,7 @@ test unequal_pad_for_addition2() { } } -test pad_for_addition_works() { +test pad_for_addition_does_works() { let b: ByteArray = #"acab" let a: ByteArray = #"cafe" let (new_a, new_b) = pad_for_addition(a, b) @@ -44,20 +44,40 @@ test emptiness_is_empty() { add(#"", #"") == #"" } -test not_equal_length_does_not_work() fail { +test adding_not_equal_length_does_not_work() fail { add(#"00", #"acab") == #"acab" } -test communitive() { - add(#"acab", #"0000") == add(#"0000", #"acab") +test add_communitive() { + add(#"acab", #"cafe") == add(#"cafe", #"acab") } -test associativity() { +test add_associativity() { ( add(#"0101", #"0202") |> add(#"0303") ) == ( add(#"0202", #"0303") |> add(#"0101") ) } -test identity() { +test add_identity() { add(#"00", #"01") == #"01" } + +test subtracting_does_work1() { + subtract(#"0177a9", #"00cafe") == #"00acab" +} + +test subtracting_does_work2() { + subtract(#"77a9", #"cafe") == #"acab" +} + +test subtracting_not_equal_length_does_not_work() fail { + subtract(#"0177a9", #"cafe") == #"acab" +} + +test subtract_is_not_communitive() fail { + subtract(#"acab", #"cafe") == add(#"cafe", #"acab") +} + +test subtract_identity() { + subtract(#"10", #"00") == #"10" +} From fde896f3380eb50a8d7e01952b10fe6b5b46b19b Mon Sep 17 00:00:00 2001 From: logicalmechanism Date: Tue, 18 Feb 2025 21:36:35 -0800 Subject: [PATCH 06/16] multiplication is at most l1 + l2 bytes --- lib/aiken/math/bitwise.ak | 25 +++++++++++++++++++++++++ lib/aiken/math/bitwise.tests.ak | 32 +++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak index 8861d39..1372586 100644 --- a/lib/aiken/math/bitwise.ak +++ b/lib/aiken/math/bitwise.ak @@ -67,3 +67,28 @@ pub fn subtract(a: ByteArray, b: ByteArray) -> ByteArray { subtract(diff_without_borrow, borrow) } } + +/// Multiplication will at most add N bytes to a bytearray for a bytearray of size N. +/// This will prepad the bytearrays to the correct length for multiplication and it +/// will correct for mismatched lengths. +/// +/// ```aiken +/// bitwise.pad_for_multiply(#"acab", #"cafe") == (#"0000acab", #"0000cafe") +/// ``` +pub fn pad_for_multiply(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { + let length_a: Int = builtin.length_of_bytearray(a) + let length_b: Int = builtin.length_of_bytearray(b) + if length_a >= length_b { + let diff: Int = length_a - length_b + ( + builtin.append_bytearray(builtin.replicate_byte(length_a, 0), a), + builtin.append_bytearray(builtin.replicate_byte(diff + length_a, 0), b), + ) + } else { + let diff: Int = length_b - length_a + ( + builtin.append_bytearray(builtin.replicate_byte(diff + length_b, 0), a), + builtin.append_bytearray(builtin.replicate_byte(length_b, 0), b), + ) + } +} diff --git a/lib/aiken/math/bitwise.tests.ak b/lib/aiken/math/bitwise.tests.ak index c742207..db5bf7d 100644 --- a/lib/aiken/math/bitwise.tests.ak +++ b/lib/aiken/math/bitwise.tests.ak @@ -1,4 +1,4 @@ -use aiken/math/bitwise.{add, pad_for_addition, subtract} +use aiken/math/bitwise.{add, pad_for_addition, pad_for_multiply, subtract} test equal_pad_for_addition() { let a: ByteArray = #"acab" @@ -81,3 +81,33 @@ test subtract_is_not_communitive() fail { test subtract_identity() { subtract(#"10", #"00") == #"10" } + +test equal_pad_for_multiply() { + let a: ByteArray = #"acab" + let b: ByteArray = #"cafe" + let (new_a, new_b) = pad_for_multiply(a, b) + and { + new_a == #"0000acab", + new_b == #"0000cafe", + } +} + +test unequal_pad_for_multiply1() { + let a: ByteArray = #"acabbeefface" + let b: ByteArray = #"cafe" + let (new_a, new_b) = pad_for_multiply(a, b) + and { + new_a == #"000000000000acabbeefface", + new_b == #"00000000000000000000cafe", + } +} + +test unequal_pad_for_multiply2() { + let b: ByteArray = #"acabbeefface" + let a: ByteArray = #"cafe" + let (new_a, new_b) = pad_for_multiply(a, b) + and { + new_a == #"00000000000000000000cafe", + new_b == #"000000000000acabbeefface", + } +} From dc9c4dbf63b003c709615201975e4714a8d0e62e Mon Sep 17 00:00:00 2001 From: logicalmechanism Date: Tue, 18 Feb 2025 21:57:05 -0800 Subject: [PATCH 07/16] probably some faster way to do muliplication but this does do arbitrary values --- lib/aiken/math/bitwise.ak | 33 +++++++++++++++++++++++++++++++++ lib/aiken/math/bitwise.tests.ak | 12 +++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak index 1372586..c2a1ae5 100644 --- a/lib/aiken/math/bitwise.ak +++ b/lib/aiken/math/bitwise.ak @@ -92,3 +92,36 @@ pub fn pad_for_multiply(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { ) } } + +pub fn multiply(a: ByteArray, b: ByteArray) -> ByteArray { + let length_a: Int = builtin.length_of_bytearray(a) + let zero: ByteArray = builtin.replicate_byte(length_a, 0) + let one: ByteArray = + builtin.append_bytearray(builtin.replicate_byte(length_a, 0), #"01") + do_multiply(a, b, zero, one) +} + +fn do_multiply( + a: ByteArray, + b: ByteArray, + acc: ByteArray, + one: ByteArray, +) -> ByteArray { + if builtin.count_set_bits(b) == 0 { + acc + } else { + let bit_set = builtin.and_bytearray(True, b, #"00000001") + let new_acc = + if builtin.count_set_bits(bit_set) > 0 { + add(acc, a) + } else { + acc + } + + let new_a = builtin.shift_bytearray(a, 1) + // left shift: multiply a by 2 + let new_b = builtin.shift_bytearray(b, -1) + // right shift: divide b by 2 + do_multiply(new_a, new_b, new_acc, one) + } +} diff --git a/lib/aiken/math/bitwise.tests.ak b/lib/aiken/math/bitwise.tests.ak index db5bf7d..2a79f85 100644 --- a/lib/aiken/math/bitwise.tests.ak +++ b/lib/aiken/math/bitwise.tests.ak @@ -1,4 +1,6 @@ -use aiken/math/bitwise.{add, pad_for_addition, pad_for_multiply, subtract} +use aiken/math/bitwise.{ + add, multiply, pad_for_addition, pad_for_multiply, subtract, +} test equal_pad_for_addition() { let a: ByteArray = #"acab" @@ -111,3 +113,11 @@ test unequal_pad_for_multiply2() { new_b == #"000000000000acabbeefface", } } + +test simple_multiply1() { + multiply(#"0000ffff", #"0000ffff") == #"fffe0001" +} + +test multiply_communitive() { + multiply(#"0000acab", #"0000cafe") == multiply(#"0000cafe", #"0000acab") +} From ec1fc88dd4f80c5ce65b729cdae61e06e6ace86a Mon Sep 17 00:00:00 2001 From: microproofs Date: Wed, 19 Feb 2025 17:09:38 -0500 Subject: [PATCH 08/16] Try out a new interface for additional bitwise operations --- aiken.toml | 2 +- lib/aiken/math/bitwise.ak | 343 ++++++++++++++++++++++---------- lib/aiken/math/bitwise.tests.ak | 237 +++++++++++----------- 3 files changed, 363 insertions(+), 219 deletions(-) diff --git a/aiken.toml b/aiken.toml index 8333752..5b312cb 100644 --- a/aiken.toml +++ b/aiken.toml @@ -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" diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak index c2a1ae5..df3461a 100644 --- a/lib/aiken/math/bitwise.ak +++ b/lib/aiken/math/bitwise.ak @@ -1,127 +1,258 @@ use aiken/builtin -/// Addition will at most add a single byte to a bytearray. This will prepad the -/// bytearrays to the correct length for addition and it will correct for mismatched -/// lengths. -/// -/// ```aiken -/// bitwise.pad_for_addition(#"acab", #"cafe") == (#"00acab", #"00cafe") -/// ``` -pub fn pad_for_addition(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { - let length_a: Int = builtin.length_of_bytearray(a) - let length_b: Int = builtin.length_of_bytearray(b) - if length_a >= length_b { - let diff: Int = length_a - length_b - ( - builtin.cons_bytearray(0, a), - builtin.append_bytearray(builtin.replicate_byte(diff + 1, 0), b), - ) - } else { - let diff: Int = length_b - length_a - ( - builtin.append_bytearray(builtin.replicate_byte(diff + 1, 0), a), - builtin.cons_bytearray(0, b), - ) +pub opaque type Intermediary { + inner: Int, +} + +pub const zero_intermediary = Intermediary { inner: 0 } + +pub const one_intermediary = Intermediary { inner: 1 } + +pub opaque type Scalar { + inner: Int, +} + +pub fn from_scalar(scalar: Scalar) -> Intermediary { + Intermediary { inner: scalar.inner } +} + +pub fn add_bits(scalar: Int, big_endian: Bool) { + fn(intermediate: Intermediary, bytes: ByteArray) -> Intermediary { + builtin.bytearray_to_integer(big_endian, bytes) + |> builtin.add_integer(intermediate.inner) + |> builtin.mod_integer(scalar) + |> Intermediary } } -/// Add two ByteArrays, a + b, using bitwise operations. The function -/// assumes fixed-width (modular) arithmetic. If arbitrary precision is required -/// use `pad_for_addition`. -/// -/// -- pad inputs for arbitrary precision -/// -/// ```aiken -/// bitwise.add(#"00acab", #"00cafe") == #"0177A9" -/// ``` -/// -/// -- otherwise -/// -/// ```aiken -/// bitwise.add(#"acab", #"cafe") == #"77A9" -/// ``` -pub fn add(a: ByteArray, b: ByteArray) -> ByteArray { - if builtin.count_set_bits(b) == 0 { - a - } else { - let carry: ByteArray = - builtin.and_bytearray(True, a, b) |> builtin.shift_bytearray(1) - let sum_without_carry: ByteArray = builtin.xor_bytearray(True, a, b) - add(sum_without_carry, carry) +pub fn add_int(scalar: Int) { + fn(intermediate: Intermediary, int: Int) -> Intermediary { + intermediate.inner + int + |> builtin.mod_integer(scalar) + |> Intermediary } } -/// Subtracts two ByteArrays, a - b, using bitwise operations. -/// -/// ```aiken -/// bitwise.subtract(#"77a9", #"cafe") == #"acab" -/// ``` -pub fn subtract(a: ByteArray, b: ByteArray) -> ByteArray { - if builtin.count_set_bits(b) == 0 { - a - } else { - let borrow: ByteArray = - builtin.and_bytearray(True, builtin.complement_bytearray(a), b) - |> builtin.shift_bytearray(1) - let diff_without_borrow: ByteArray = builtin.xor_bytearray(True, a, b) - subtract(diff_without_borrow, borrow) +pub fn add_intermediary(scalar: Int) { + fn(intermediate: Intermediary, other: Intermediary) -> Intermediary { + intermediate.inner + other.inner + |> builtin.mod_integer(scalar) + |> Intermediary } } -/// Multiplication will at most add N bytes to a bytearray for a bytearray of size N. -/// This will prepad the bytearrays to the correct length for multiplication and it -/// will correct for mismatched lengths. -/// -/// ```aiken -/// bitwise.pad_for_multiply(#"acab", #"cafe") == (#"0000acab", #"0000cafe") -/// ``` -pub fn pad_for_multiply(a: ByteArray, b: ByteArray) -> (ByteArray, ByteArray) { - let length_a: Int = builtin.length_of_bytearray(a) - let length_b: Int = builtin.length_of_bytearray(b) - if length_a >= length_b { - let diff: Int = length_a - length_b - ( - builtin.append_bytearray(builtin.replicate_byte(length_a, 0), a), - builtin.append_bytearray(builtin.replicate_byte(diff + length_a, 0), b), - ) +pub fn sub_bits(scalar: Int, big_endian: Bool) { + fn(intermediate: Intermediary, bytes: ByteArray) -> Intermediary { + builtin.bytearray_to_integer(big_endian, bytes) + |> builtin.subtract_integer(intermediate.inner) + |> builtin.mod_integer(scalar) + |> Intermediary + } +} + +pub fn sub_int(scalar: Int) { + fn(intermediate: Intermediary, int: Int) -> Intermediary { + intermediate.inner - int + |> builtin.mod_integer(scalar) + |> Intermediary + } +} + +pub fn sub_intermediary(scalar: Int) { + fn(intermediate: Intermediary, other: Intermediary) -> Intermediary { + intermediate.inner - other.inner + |> builtin.mod_integer(scalar) + |> Intermediary + } +} + +pub fn mul_bits(scalar: Int, big_endian: Bool) { + fn(intermediate: Intermediary, bytes: ByteArray) -> Intermediary { + builtin.bytearray_to_integer(big_endian, bytes) + |> builtin.multiply_integer(intermediate.inner) + |> builtin.mod_integer(scalar) + |> Intermediary + } +} + +pub fn mul_int(scalar: Int) { + fn(intermediate: Intermediary, int: Int) -> Intermediary { + intermediate.inner * int + |> builtin.mod_integer(scalar) + |> Intermediary + } +} + +pub fn mul_intermediary(scalar: Int) { + fn(intermediate: Intermediary, other: Intermediary) -> Intermediary { + intermediate.inner * other.inner + |> builtin.mod_integer(scalar) + |> Intermediary + } +} + +pub fn scale(self: Intermediary, e: Int, scalar: Int) -> Intermediary { + if e < 0 { + zero_intermediary + } else if e == 0 { + one_intermediary + } else if e % 2 == 0 { + scale(mul_intermediary(scalar)(self, self), e / 2, scalar) } else { - let diff: Int = length_b - length_a - ( - builtin.append_bytearray(builtin.replicate_byte(diff + length_b, 0), a), - builtin.append_bytearray(builtin.replicate_byte(length_b, 0), b), + mul_intermediary(scalar)( + self, + scale(mul_intermediary(scalar)(self, self), ( e - 1 ) / 2, scalar), ) } } -pub fn multiply(a: ByteArray, b: ByteArray) -> ByteArray { - let length_a: Int = builtin.length_of_bytearray(a) - let zero: ByteArray = builtin.replicate_byte(length_a, 0) - let one: ByteArray = - builtin.append_bytearray(builtin.replicate_byte(length_a, 0), #"01") - do_multiply(a, b, zero, one) +/// 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(scalar: Int) { + fn(self: Intermediary, k: Int) -> Intermediary { + if k == 0 { + self + } else { + do_scale2(mul_intermediary(scalar)(self, self), k - 1, scalar) + } + } } -fn do_multiply( - a: ByteArray, - b: ByteArray, - acc: ByteArray, - one: ByteArray, -) -> ByteArray { - if builtin.count_set_bits(b) == 0 { - acc +fn do_scale2(self: Intermediary, k: Int, scalar) -> Intermediary { + if k == 0 { + self } else { - let bit_set = builtin.and_bytearray(True, b, #"00000001") - let new_acc = - if builtin.count_set_bits(bit_set) > 0 { - add(acc, a) - } else { - acc - } - - let new_a = builtin.shift_bytearray(a, 1) - // left shift: multiply a by 2 - let new_b = builtin.shift_bytearray(b, -1) - // right shift: divide b by 2 - do_multiply(new_a, new_b, new_acc, one) + do_scale2(mul_intermediary(scalar)(self, self), k - 1, scalar) + } +} + +pub fn neg(scalar: Int) { + fn(intermediate: Intermediary) -> Intermediary { + scalar - intermediate.inner + |> Intermediary } } + +pub opaque type Hash256 { + inner: ByteArray, +} + +pub const hash256_field = + builtin.replicate_byte(32, 0) + |> builtin.cons_bytearray(1, _) + |> builtin.bytearray_to_integer(True, _) + +pub const hash224_field = + builtin.replicate_byte(28, 0) + |> builtin.cons_bytearray(1, _) + |> builtin.bytearray_to_integer(True, _) + +/// The prime number defining the scalar field of the BLS12-381 curve. +pub const bls381_prime_field = + 52435875175126190479447740508185965837690552500527637822603658699938581184513 + +pub fn to_bits256(intermediate: Intermediary) -> ByteArray { + intermediate.inner + |> builtin.integer_to_bytearray(True, 32, _) +} + +pub fn to_int256(intermediate: Intermediary) -> Int { + intermediate.inner +} + +pub fn bits256_to_intermediary(bytes: ByteArray) -> Intermediary { + bytes + |> builtin.bytearray_to_integer(True, _) + |> builtin.mod_integer(hash256_field) + |> Intermediary +} + +pub fn int256_to_intermediary(int: Int) -> Intermediary { + int % hash256_field + |> Intermediary +} + +pub fn add_bits256( + intermediate: Intermediary, + bytes: ByteArray, +) -> Intermediary { + let add_bits = add_bits(hash256_field, True) + + add_bits(intermediate, bytes) +} + +pub fn add_int256( + intermediate: Intermediary, + int: Int, +) -> Intermediary { + let add_int = add_int(hash256_field) + + add_int(intermediate, int) +} + +pub fn sub_int256( + intermediate: Intermediary, + int: Int, +) -> Intermediary { + let sub_int = sub_int(hash256_field) + + sub_int(intermediate, int) +} + +pub fn sub_bits256( + intermediate: Intermediary, + bytes: ByteArray, +) -> Intermediary { + let sub_bits = sub_bits(hash256_field, True) + + sub_bits(intermediate, bytes) +} + +pub fn mul_bits256( + intermediate: Intermediary, + bytes: ByteArray, +) -> Intermediary { + let mul_bits = mul_bits(hash256_field, True) + + mul_bits(intermediate, bytes) +} + +pub fn mul_int256( + intermediate: Intermediary, + int: Int, +) -> Intermediary { + let mul_int = mul_int(hash256_field) + + mul_int(intermediate, int) +} + +pub fn neg_256(intermediate: Intermediary) -> Intermediary { + let neg = neg(hash256_field) + + neg(intermediate) +} + +pub opaque type Hash224 { + inner: ByteArray, +} + +pub fn to_bits224(intermediate: Intermediary) -> ByteArray { + intermediate.inner + |> builtin.integer_to_bytearray(True, 28, _) +} + +pub fn to_int224(intermediate: Intermediary) -> Int { + intermediate.inner +} + +pub fn bits224_to_intermediary(bytes: ByteArray) -> Intermediary { + bytes + |> builtin.bytearray_to_integer(True, _) + |> builtin.mod_integer(hash224_field) + |> Intermediary +} + +pub fn int224_to_intermediary(int: Int) -> Intermediary { + int % hash256_field + |> Intermediary +} diff --git a/lib/aiken/math/bitwise.tests.ak b/lib/aiken/math/bitwise.tests.ak index 2a79f85..728ade3 100644 --- a/lib/aiken/math/bitwise.tests.ak +++ b/lib/aiken/math/bitwise.tests.ak @@ -1,123 +1,136 @@ -use aiken/math/bitwise.{ - add, multiply, pad_for_addition, pad_for_multiply, subtract, -} +use aiken/math/bitwise.{add_bits256, bits256_to_intermediary, to_bits256} test equal_pad_for_addition() { let a: ByteArray = #"acab" let b: ByteArray = #"cafe" - let (new_a, new_b) = pad_for_addition(a, b) - and { - new_a == #"00acab", - new_b == #"00cafe", - } -} - -test unequal_pad_for_addition1() { - let a: ByteArray = #"acabbeefface" - let b: ByteArray = #"cafe" - let (new_a, new_b) = pad_for_addition(a, b) - and { - new_a == #"00acabbeefface", - new_b == #"0000000000cafe", - } -} - -test unequal_pad_for_addition2() { - let b: ByteArray = #"acabbeefface" - let a: ByteArray = #"cafe" - let (new_a, new_b) = pad_for_addition(a, b) - and { - new_a == #"0000000000cafe", - new_b == #"00acabbeefface", - } -} - -test pad_for_addition_does_works() { - let b: ByteArray = #"acab" - let a: ByteArray = #"cafe" - let (new_a, new_b) = pad_for_addition(a, b) - and { - add(a, b) == #"77a9", - add(new_a, new_b) == #"0177a9", - } -} -test emptiness_is_empty() { - add(#"", #"") == #"" -} - -test adding_not_equal_length_does_not_work() fail { - add(#"00", #"acab") == #"acab" -} - -test add_communitive() { - add(#"acab", #"cafe") == add(#"cafe", #"acab") -} - -test add_associativity() { - ( add(#"0101", #"0202") |> add(#"0303") ) == ( - add(#"0202", #"0303") |> add(#"0101") - ) -} - -test add_identity() { - add(#"00", #"01") == #"01" -} + let x = + a + |> bits256_to_intermediary + |> add_bits256(b) + |> to_bits256 -test subtracting_does_work1() { - subtract(#"0177a9", #"00cafe") == #"00acab" + x == #"00000000000000000000000000000000000000000000000000000000000177a9" } -test subtracting_does_work2() { - subtract(#"77a9", #"cafe") == #"acab" -} - -test subtracting_not_equal_length_does_not_work() fail { - subtract(#"0177a9", #"cafe") == #"acab" -} - -test subtract_is_not_communitive() fail { - subtract(#"acab", #"cafe") == add(#"cafe", #"acab") -} - -test subtract_identity() { - subtract(#"10", #"00") == #"10" -} - -test equal_pad_for_multiply() { - let a: ByteArray = #"acab" - let b: ByteArray = #"cafe" - let (new_a, new_b) = pad_for_multiply(a, b) - and { - new_a == #"0000acab", - new_b == #"0000cafe", - } -} - -test unequal_pad_for_multiply1() { +test unequal_pad_for_addition() { let a: ByteArray = #"acabbeefface" let b: ByteArray = #"cafe" - let (new_a, new_b) = pad_for_multiply(a, b) - and { - new_a == #"000000000000acabbeefface", - new_b == #"00000000000000000000cafe", - } -} -test unequal_pad_for_multiply2() { - let b: ByteArray = #"acabbeefface" - let a: ByteArray = #"cafe" - let (new_a, new_b) = pad_for_multiply(a, b) - and { - new_a == #"00000000000000000000cafe", - new_b == #"000000000000acabbeefface", - } -} - -test simple_multiply1() { - multiply(#"0000ffff", #"0000ffff") == #"fffe0001" -} - -test multiply_communitive() { - multiply(#"0000acab", #"0000cafe") == multiply(#"0000cafe", #"0000acab") -} + let x = + a + |> bits256_to_intermediary + |> add_bits256(b) + |> to_bits256 + + x == #"0000000000000000000000000000000000000000000000000000acabbef0c5cc" +} +// test unequal_pad_for_addition1() { +// let a: ByteArray = #"acabbeefface" +// let b: ByteArray = #"cafe" +// let (new_a, new_b) = pad_for_addition(a, b) +// and { +// new_a == #"00acabbeefface", +// new_b == #"0000000000cafe", +// } +// } + +// test unequal_pad_for_addition2() { +// let b: ByteArray = #"acabbeefface" +// let a: ByteArray = #"cafe" +// let (new_a, new_b) = pad_for_addition(a, b) +// and { +// new_a == #"0000000000cafe", +// new_b == #"00acabbeefface", +// } +// } + +// test pad_for_addition_does_works() { +// let b: ByteArray = #"acab" +// let a: ByteArray = #"cafe" +// let (new_a, new_b) = pad_for_addition(a, b) +// and { +// add(a, b) == #"77a9", +// add(new_a, new_b) == #"0177a9", +// } +// } + +// test emptiness_is_empty() { +// add(#"", #"") == #"" +// } + +// test adding_not_equal_length_does_not_work() fail { +// add(#"00", #"acab") == #"acab" +// } + +// test add_communitive() { +// add(#"acab", #"cafe") == add(#"cafe", #"acab") +// } + +// test add_associativity() { +// ( add(#"0101", #"0202") |> add(#"0303") ) == ( +// add(#"0202", #"0303") |> add(#"0101") +// ) +// } + +// test add_identity() { +// add(#"00", #"01") == #"01" +// } + +// test subtracting_does_work1() { +// subtract(#"0177a9", #"00cafe") == #"00acab" +// } + +// test subtracting_does_work2() { +// subtract(#"77a9", #"cafe") == #"acab" +// } + +// test subtracting_not_equal_length_does_not_work() fail { +// subtract(#"0177a9", #"cafe") == #"acab" +// } + +// test subtract_is_not_communitive() fail { +// subtract(#"acab", #"cafe") == add(#"cafe", #"acab") +// } + +// test subtract_identity() { +// subtract(#"10", #"00") == #"10" +// } + +// test equal_pad_for_multiply() { +// let a: ByteArray = #"acab" +// let b: ByteArray = #"cafe" +// let (new_a, new_b) = pad_for_multiply(a, b) +// and { +// new_a == #"0000acab", +// new_b == #"0000cafe", +// } +// } + +// test unequal_pad_for_multiply1() { +// let a: ByteArray = #"acabbeefface" +// let b: ByteArray = #"cafe" +// let (new_a, new_b) = pad_for_multiply(a, b) +// and { +// new_a == #"000000000000acabbeefface", +// new_b == #"00000000000000000000cafe", +// } +// } + +// test unequal_pad_for_multiply2() { +// let b: ByteArray = #"acabbeefface" +// let a: ByteArray = #"cafe" +// let (new_a, new_b) = pad_for_multiply(a, b) +// and { +// new_a == #"00000000000000000000cafe", +// new_b == #"000000000000acabbeefface", +// } +// } + +// test simple_multiply1() { +// multiply(#"0000ffff", #"0000ffff") == #"fffe0001" +// } + +// test multiply_communitive() { +// multiply(#"0000acab", #"0000cafe") == multiply(#"0000cafe", #"0000acab") +// } From 9b563b15efed4ad0e3c7edb19e8b12d9942a9c48 Mon Sep 17 00:00:00 2001 From: microproofs Date: Thu, 20 Feb 2025 11:44:45 -0500 Subject: [PATCH 09/16] Update to use consts for performance --- lib/aiken/math/bitwise.ak | 102 ++++++++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 21 deletions(-) diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak index df3461a..90dcb73 100644 --- a/lib/aiken/math/bitwise.ak +++ b/lib/aiken/math/bitwise.ak @@ -172,64 +172,64 @@ pub fn int256_to_intermediary(int: Int) -> Intermediary { |> Intermediary } +const add_bit256 = add_bits(hash256_field, True) + pub fn add_bits256( intermediate: Intermediary, bytes: ByteArray, ) -> Intermediary { - let add_bits = add_bits(hash256_field, True) - - add_bits(intermediate, bytes) + add_bit256(intermediate, bytes) } +const add_i256 = add_int(hash256_field) + pub fn add_int256( intermediate: Intermediary, int: Int, ) -> Intermediary { - let add_int = add_int(hash256_field) - - add_int(intermediate, int) + add_i256(intermediate, int) } +const sub_i256 = sub_int(hash256_field) + pub fn sub_int256( intermediate: Intermediary, int: Int, ) -> Intermediary { - let sub_int = sub_int(hash256_field) - - sub_int(intermediate, int) + sub_i256(intermediate, int) } +const sub_bit256 = sub_bits(hash256_field, True) + pub fn sub_bits256( intermediate: Intermediary, bytes: ByteArray, ) -> Intermediary { - let sub_bits = sub_bits(hash256_field, True) - - sub_bits(intermediate, bytes) + sub_bit256(intermediate, bytes) } +const mul_bit256 = mul_bits(hash256_field, True) + pub fn mul_bits256( intermediate: Intermediary, bytes: ByteArray, ) -> Intermediary { - let mul_bits = mul_bits(hash256_field, True) - - mul_bits(intermediate, bytes) + mul_bit256(intermediate, bytes) } +const mul_i256 = mul_int(hash256_field) + pub fn mul_int256( intermediate: Intermediary, int: Int, ) -> Intermediary { - let mul_int = mul_int(hash256_field) - - mul_int(intermediate, int) + mul_i256(intermediate, int) } -pub fn neg_256(intermediate: Intermediary) -> Intermediary { - let neg = neg(hash256_field) +const neg256 = neg(hash256_field) - neg(intermediate) +pub fn neg_256(intermediate: Intermediary) -> Intermediary { + neg256(intermediate) } pub opaque type Hash224 { @@ -256,3 +256,63 @@ pub fn int224_to_intermediary(int: Int) -> Intermediary { int % hash256_field |> Intermediary } + +const add_bit224 = add_bits(hash224_field, True) + +pub fn add_bits224( + intermediate: Intermediary, + bytes: ByteArray, +) -> Intermediary { + add_bit224(intermediate, bytes) +} + +const add_i224 = add_int(hash224_field) + +pub fn add_int224( + intermediate: Intermediary, + int: Int, +) -> Intermediary { + add_i224(intermediate, int) +} + +const sub_i224 = sub_int(hash224_field) + +pub fn sub_int224( + intermediate: Intermediary, + int: Int, +) -> Intermediary { + sub_i224(intermediate, int) +} + +const sub_bit224 = sub_bits(hash224_field, True) + +pub fn sub_bits224( + intermediate: Intermediary, + bytes: ByteArray, +) -> Intermediary { + sub_bit224(intermediate, bytes) +} + +const mul_bit224 = mul_bits(hash224_field, True) + +pub fn mul_bits224( + intermediate: Intermediary, + bytes: ByteArray, +) -> Intermediary { + mul_bit224(intermediate, bytes) +} + +const mul_i224 = mul_int(hash224_field) + +pub fn mul_int224( + intermediate: Intermediary, + int: Int, +) -> Intermediary { + mul_i224(intermediate, int) +} + +const neg224 = neg(hash224_field) + +pub fn neg_224(intermediate: Intermediary) -> Intermediary { + neg224(intermediate) +} From f6f771dabd99544648a5cf8d4234ae2b7201b33f Mon Sep 17 00:00:00 2001 From: microproofs Date: Thu, 20 Feb 2025 12:29:43 -0500 Subject: [PATCH 10/16] Add a few more functions --- lib/aiken/math/bitwise.ak | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak index 90dcb73..902fe83 100644 --- a/lib/aiken/math/bitwise.ak +++ b/lib/aiken/math/bitwise.ak @@ -316,3 +316,27 @@ const neg224 = neg(hash224_field) pub fn neg_224(intermediate: Intermediary) -> Intermediary { neg224(intermediate) } + +pub fn and_bytes( + left: ByteArray, + right: ByteArray, + extend_shorter: Bool, +) -> ByteArray { + builtin.and_bytearray(extend_shorter, left, right) +} + +pub fn or_bytes( + left: ByteArray, + right: ByteArray, + extend_shorter: Bool, +) -> ByteArray { + builtin.or_bytearray(extend_shorter, left, right) +} + +pub fn xor_bytes( + left: ByteArray, + right: ByteArray, + extend_shorter: Bool, +) -> ByteArray { + builtin.xor_bytearray(extend_shorter, left, right) +} From a27c334fd9b04c2d73d54d4f509ff9b20c1909a1 Mon Sep 17 00:00:00 2001 From: microproofs Date: Wed, 26 Feb 2025 11:12:23 -0500 Subject: [PATCH 11/16] Tweak interface to have separate files for different bytearray hash sizes --- lib/aiken/crypto/bitwise.ak | 135 +++++++ lib/aiken/crypto/int224.ak | 89 +++++ lib/aiken/crypto/int256.ak | 89 +++++ .../int256.tests.ak} | 14 +- lib/aiken/math/bitwise.ak | 342 ------------------ lib/aiken/primitive/bytearray.ak | 12 + 6 files changed, 332 insertions(+), 349 deletions(-) create mode 100644 lib/aiken/crypto/bitwise.ak create mode 100644 lib/aiken/crypto/int224.ak create mode 100644 lib/aiken/crypto/int256.ak rename lib/aiken/{math/bitwise.tests.ak => crypto/int256.tests.ak} (93%) delete mode 100644 lib/aiken/math/bitwise.ak diff --git a/lib/aiken/crypto/bitwise.ak b/lib/aiken/crypto/bitwise.ak new file mode 100644 index 0000000..411ab00 --- /dev/null +++ b/lib/aiken/crypto/bitwise.ak @@ -0,0 +1,135 @@ +use aiken/builtin + +pub opaque type State { + inner: Int, +} + +pub const zero_intermediary = State { inner: 0 } + +pub const one_intermediary = State { inner: 1 } + +pub fn add_bits(scalar: Int, big_endian: Bool) { + fn(intermediate: State, bytes: ByteArray) -> State { + builtin.bytearray_to_integer(big_endian, bytes) + |> builtin.add_integer(intermediate.inner) + |> builtin.mod_integer(scalar) + |> State + } +} + +pub fn add_int(scalar: Int) { + fn(intermediate: State, int: Int) -> State { + intermediate.inner + int + |> builtin.mod_integer(scalar) + |> State + } +} + +pub fn add_intermediary(scalar: Int) { + fn(intermediate: State, other: State) -> State { + intermediate.inner + other.inner + |> builtin.mod_integer(scalar) + |> State + } +} + +pub fn sub_bits(scalar: Int, big_endian: Bool) { + fn(intermediate: State, bytes: ByteArray) -> State { + builtin.bytearray_to_integer(big_endian, bytes) + |> builtin.subtract_integer(intermediate.inner) + |> builtin.mod_integer(scalar) + |> State + } +} + +pub fn sub_int(scalar: Int) { + fn(intermediate: State, int: Int) -> State { + intermediate.inner - int + |> builtin.mod_integer(scalar) + |> State + } +} + +pub fn sub_intermediary(scalar: Int) { + fn(intermediate: State, other: State) -> State { + intermediate.inner - other.inner + |> builtin.mod_integer(scalar) + |> State + } +} + +pub fn mul_bits(scalar: Int, big_endian: Bool) { + fn(intermediate: State, bytes: ByteArray) -> State { + builtin.bytearray_to_integer(big_endian, bytes) + |> builtin.multiply_integer(intermediate.inner) + |> builtin.mod_integer(scalar) + |> State + } +} + +pub fn mul_int(scalar: Int) { + fn(intermediate: State, int: Int) -> State { + intermediate.inner * int + |> builtin.mod_integer(scalar) + |> State + } +} + +pub fn mul_intermediary(scalar: Int) { + fn(intermediate: State, other: State) -> State { + intermediate.inner * other.inner + |> builtin.mod_integer(scalar) + |> State + } +} + +pub fn scale(self: State, e: Int, scalar: Int) -> State { + if e < 0 { + zero_intermediary + } else if e == 0 { + one_intermediary + } else if e % 2 == 0 { + scale(mul_intermediary(scalar)(self, self), e / 2, scalar) + } else { + mul_intermediary(scalar)( + self, + scale(mul_intermediary(scalar)(self, self), ( e - 1 ) / 2, scalar), + ) + } +} + +/// 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(scalar: Int) { + fn(self: State, k: Int) -> State { + if k == 0 { + self + } else { + do_scale2(mul_intermediary(scalar)(self, self), k - 1, scalar) + } + } +} + +fn do_scale2(self: State, k: Int, scalar) -> State { + if k == 0 { + self + } else { + do_scale2(mul_intermediary(scalar)(self, self), k - 1, scalar) + } +} + +pub fn neg(scalar: Int) { + fn(intermediate: State) -> State { + scalar - intermediate.inner + |> State + } +} + +pub fn to_int(intermediate: State) -> Int { + intermediate.inner +} + +pub fn from_int(int: Int, field: Int) -> State { + int % field + |> State +} diff --git a/lib/aiken/crypto/int224.ak b/lib/aiken/crypto/int224.ak new file mode 100644 index 0000000..34cf08f --- /dev/null +++ b/lib/aiken/crypto/int224.ak @@ -0,0 +1,89 @@ +use aiken/builtin +use aiken/crypto/bitwise.{ + State, add_bits as addbit, add_int as addint, mul_bits as mulbit, + mul_int as mulint, neg as negbit, sub_bits as subbit, sub_int as subint, +} + +pub type Hash224 = + ByteArray + +pub const hash224_field = + builtin.replicate_byte(28, 0) + |> builtin.cons_bytearray(1, _) + |> builtin.bytearray_to_integer(True, _) + +pub fn to_bytes(intermediate: State) -> ByteArray { + bitwise.to_int(intermediate) + |> builtin.integer_to_bytearray(True, 28, _) +} + +pub fn to_int(intermediate: State) -> Int { + bitwise.to_int(intermediate) +} + +pub fn from_bytes(bytes: Hash224) -> State { + bytes + |> builtin.bytearray_to_integer(True, _) + |> bitwise.from_int(hash224_field) +} + +pub fn from_int(int: Int) -> State { + bitwise.from_int(int, hash224_field) +} + +type Bitwise224Bytes = + fn(State, ByteArray) -> State + +type Bitwise224Int = + fn(State, Int) -> State + +const add_bit224: Bitwise224Bytes = addbit(hash224_field, True) + +pub fn add_bytes( + intermediate: State, + bytes: ByteArray, +) -> State { + add_bit224(intermediate, bytes) +} + +const add_i224: Bitwise224Int = addint(hash224_field) + +pub fn add_int(intermediate: State, int: Int) -> State { + add_i224(intermediate, int) +} + +const sub_i224: Bitwise224Int = subint(hash224_field) + +pub fn sub_int(intermediate: State, int: Int) -> State { + sub_i224(intermediate, int) +} + +const sub_bit224: Bitwise224Bytes = subbit(hash224_field, True) + +pub fn sub_bytes( + intermediate: State, + bytes: ByteArray, +) -> State { + sub_bit224(intermediate, bytes) +} + +const mul_bit224: Bitwise224Bytes = mulbit(hash224_field, True) + +pub fn mul_bytes( + intermediate: State, + bytes: ByteArray, +) -> State { + mul_bit224(intermediate, bytes) +} + +const mul_i224: Bitwise224Int = mulint(hash224_field) + +pub fn mul_int(intermediate: State, int: Int) -> State { + mul_i224(intermediate, int) +} + +const neg224: fn(State) -> State = negbit(hash224_field) + +pub fn neg(intermediate: State) -> State { + neg224(intermediate) +} diff --git a/lib/aiken/crypto/int256.ak b/lib/aiken/crypto/int256.ak new file mode 100644 index 0000000..40e9117 --- /dev/null +++ b/lib/aiken/crypto/int256.ak @@ -0,0 +1,89 @@ +use aiken/builtin +use aiken/crypto/bitwise.{ + State, add_bits as addbit, add_int as addint, mul_bits as mulbit, + mul_int as mulint, neg as negbit, sub_bits as subbit, sub_int as subint, +} + +pub type Hash256 = + ByteArray + +pub const hash256_field = + builtin.replicate_byte(32, 0) + |> builtin.cons_bytearray(1, _) + |> builtin.bytearray_to_integer(True, _) + +pub fn to_bytes(intermediate: State) -> ByteArray { + bitwise.to_int(intermediate) + |> builtin.integer_to_bytearray(True, 32, _) +} + +pub fn to_int(intermediate: State) -> Int { + bitwise.to_int(intermediate) +} + +pub fn from_bytes(bytes: Hash256) -> State { + bytes + |> builtin.bytearray_to_integer(True, _) + |> bitwise.from_int(hash256_field) +} + +pub fn from_int(int: Int) -> State { + bitwise.from_int(int, hash256_field) +} + +type Bitwise256Bytes = + fn(State, ByteArray) -> State + +type Bitwise256Int = + fn(State, Int) -> State + +const add_bit256: Bitwise256Bytes = addbit(hash256_field, True) + +pub fn add_bytes( + intermediate: State, + bytes: ByteArray, +) -> State { + add_bit256(intermediate, bytes) +} + +const add_i256: Bitwise256Int = addint(hash256_field) + +pub fn add_int(intermediate: State, int: Int) -> State { + add_i256(intermediate, int) +} + +const sub_i256: Bitwise256Int = subint(hash256_field) + +pub fn sub_int(intermediate: State, int: Int) -> State { + sub_i256(intermediate, int) +} + +const sub_bit256: Bitwise256Bytes = subbit(hash256_field, True) + +pub fn sub_bytes( + intermediate: State, + bytes: ByteArray, +) -> State { + sub_bit256(intermediate, bytes) +} + +const mul_bit256: Bitwise256Bytes = mulbit(hash256_field, True) + +pub fn mul_bytes( + intermediate: State, + bytes: ByteArray, +) -> State { + mul_bit256(intermediate, bytes) +} + +const mul_i256: Bitwise256Int = mulint(hash256_field) + +pub fn mul_int(intermediate: State, int: Int) -> State { + mul_i256(intermediate, int) +} + +const neg256: fn(State) -> State = negbit(hash256_field) + +pub fn neg(intermediate: State) -> State { + neg256(intermediate) +} diff --git a/lib/aiken/math/bitwise.tests.ak b/lib/aiken/crypto/int256.tests.ak similarity index 93% rename from lib/aiken/math/bitwise.tests.ak rename to lib/aiken/crypto/int256.tests.ak index 728ade3..96c3738 100644 --- a/lib/aiken/math/bitwise.tests.ak +++ b/lib/aiken/crypto/int256.tests.ak @@ -1,4 +1,4 @@ -use aiken/math/bitwise.{add_bits256, bits256_to_intermediary, to_bits256} +use aiken/crypto/int256.{add_bytes, from_bytes, to_bytes} test equal_pad_for_addition() { let a: ByteArray = #"acab" @@ -6,9 +6,9 @@ test equal_pad_for_addition() { let x = a - |> bits256_to_intermediary - |> add_bits256(b) - |> to_bits256 + |> from_bytes + |> add_bytes(b) + |> to_bytes x == #"00000000000000000000000000000000000000000000000000000000000177a9" } @@ -19,9 +19,9 @@ test unequal_pad_for_addition() { let x = a - |> bits256_to_intermediary - |> add_bits256(b) - |> to_bits256 + |> from_bytes + |> add_bytes(b) + |> to_bytes x == #"0000000000000000000000000000000000000000000000000000acabbef0c5cc" } diff --git a/lib/aiken/math/bitwise.ak b/lib/aiken/math/bitwise.ak deleted file mode 100644 index 902fe83..0000000 --- a/lib/aiken/math/bitwise.ak +++ /dev/null @@ -1,342 +0,0 @@ -use aiken/builtin - -pub opaque type Intermediary { - inner: Int, -} - -pub const zero_intermediary = Intermediary { inner: 0 } - -pub const one_intermediary = Intermediary { inner: 1 } - -pub opaque type Scalar { - inner: Int, -} - -pub fn from_scalar(scalar: Scalar) -> Intermediary { - Intermediary { inner: scalar.inner } -} - -pub fn add_bits(scalar: Int, big_endian: Bool) { - fn(intermediate: Intermediary, bytes: ByteArray) -> Intermediary { - builtin.bytearray_to_integer(big_endian, bytes) - |> builtin.add_integer(intermediate.inner) - |> builtin.mod_integer(scalar) - |> Intermediary - } -} - -pub fn add_int(scalar: Int) { - fn(intermediate: Intermediary, int: Int) -> Intermediary { - intermediate.inner + int - |> builtin.mod_integer(scalar) - |> Intermediary - } -} - -pub fn add_intermediary(scalar: Int) { - fn(intermediate: Intermediary, other: Intermediary) -> Intermediary { - intermediate.inner + other.inner - |> builtin.mod_integer(scalar) - |> Intermediary - } -} - -pub fn sub_bits(scalar: Int, big_endian: Bool) { - fn(intermediate: Intermediary, bytes: ByteArray) -> Intermediary { - builtin.bytearray_to_integer(big_endian, bytes) - |> builtin.subtract_integer(intermediate.inner) - |> builtin.mod_integer(scalar) - |> Intermediary - } -} - -pub fn sub_int(scalar: Int) { - fn(intermediate: Intermediary, int: Int) -> Intermediary { - intermediate.inner - int - |> builtin.mod_integer(scalar) - |> Intermediary - } -} - -pub fn sub_intermediary(scalar: Int) { - fn(intermediate: Intermediary, other: Intermediary) -> Intermediary { - intermediate.inner - other.inner - |> builtin.mod_integer(scalar) - |> Intermediary - } -} - -pub fn mul_bits(scalar: Int, big_endian: Bool) { - fn(intermediate: Intermediary, bytes: ByteArray) -> Intermediary { - builtin.bytearray_to_integer(big_endian, bytes) - |> builtin.multiply_integer(intermediate.inner) - |> builtin.mod_integer(scalar) - |> Intermediary - } -} - -pub fn mul_int(scalar: Int) { - fn(intermediate: Intermediary, int: Int) -> Intermediary { - intermediate.inner * int - |> builtin.mod_integer(scalar) - |> Intermediary - } -} - -pub fn mul_intermediary(scalar: Int) { - fn(intermediate: Intermediary, other: Intermediary) -> Intermediary { - intermediate.inner * other.inner - |> builtin.mod_integer(scalar) - |> Intermediary - } -} - -pub fn scale(self: Intermediary, e: Int, scalar: Int) -> Intermediary { - if e < 0 { - zero_intermediary - } else if e == 0 { - one_intermediary - } else if e % 2 == 0 { - scale(mul_intermediary(scalar)(self, self), e / 2, scalar) - } else { - mul_intermediary(scalar)( - self, - scale(mul_intermediary(scalar)(self, self), ( e - 1 ) / 2, scalar), - ) - } -} - -/// 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(scalar: Int) { - fn(self: Intermediary, k: Int) -> Intermediary { - if k == 0 { - self - } else { - do_scale2(mul_intermediary(scalar)(self, self), k - 1, scalar) - } - } -} - -fn do_scale2(self: Intermediary, k: Int, scalar) -> Intermediary { - if k == 0 { - self - } else { - do_scale2(mul_intermediary(scalar)(self, self), k - 1, scalar) - } -} - -pub fn neg(scalar: Int) { - fn(intermediate: Intermediary) -> Intermediary { - scalar - intermediate.inner - |> Intermediary - } -} - -pub opaque type Hash256 { - inner: ByteArray, -} - -pub const hash256_field = - builtin.replicate_byte(32, 0) - |> builtin.cons_bytearray(1, _) - |> builtin.bytearray_to_integer(True, _) - -pub const hash224_field = - builtin.replicate_byte(28, 0) - |> builtin.cons_bytearray(1, _) - |> builtin.bytearray_to_integer(True, _) - -/// The prime number defining the scalar field of the BLS12-381 curve. -pub const bls381_prime_field = - 52435875175126190479447740508185965837690552500527637822603658699938581184513 - -pub fn to_bits256(intermediate: Intermediary) -> ByteArray { - intermediate.inner - |> builtin.integer_to_bytearray(True, 32, _) -} - -pub fn to_int256(intermediate: Intermediary) -> Int { - intermediate.inner -} - -pub fn bits256_to_intermediary(bytes: ByteArray) -> Intermediary { - bytes - |> builtin.bytearray_to_integer(True, _) - |> builtin.mod_integer(hash256_field) - |> Intermediary -} - -pub fn int256_to_intermediary(int: Int) -> Intermediary { - int % hash256_field - |> Intermediary -} - -const add_bit256 = add_bits(hash256_field, True) - -pub fn add_bits256( - intermediate: Intermediary, - bytes: ByteArray, -) -> Intermediary { - add_bit256(intermediate, bytes) -} - -const add_i256 = add_int(hash256_field) - -pub fn add_int256( - intermediate: Intermediary, - int: Int, -) -> Intermediary { - add_i256(intermediate, int) -} - -const sub_i256 = sub_int(hash256_field) - -pub fn sub_int256( - intermediate: Intermediary, - int: Int, -) -> Intermediary { - sub_i256(intermediate, int) -} - -const sub_bit256 = sub_bits(hash256_field, True) - -pub fn sub_bits256( - intermediate: Intermediary, - bytes: ByteArray, -) -> Intermediary { - sub_bit256(intermediate, bytes) -} - -const mul_bit256 = mul_bits(hash256_field, True) - -pub fn mul_bits256( - intermediate: Intermediary, - bytes: ByteArray, -) -> Intermediary { - mul_bit256(intermediate, bytes) -} - -const mul_i256 = mul_int(hash256_field) - -pub fn mul_int256( - intermediate: Intermediary, - int: Int, -) -> Intermediary { - mul_i256(intermediate, int) -} - -const neg256 = neg(hash256_field) - -pub fn neg_256(intermediate: Intermediary) -> Intermediary { - neg256(intermediate) -} - -pub opaque type Hash224 { - inner: ByteArray, -} - -pub fn to_bits224(intermediate: Intermediary) -> ByteArray { - intermediate.inner - |> builtin.integer_to_bytearray(True, 28, _) -} - -pub fn to_int224(intermediate: Intermediary) -> Int { - intermediate.inner -} - -pub fn bits224_to_intermediary(bytes: ByteArray) -> Intermediary { - bytes - |> builtin.bytearray_to_integer(True, _) - |> builtin.mod_integer(hash224_field) - |> Intermediary -} - -pub fn int224_to_intermediary(int: Int) -> Intermediary { - int % hash256_field - |> Intermediary -} - -const add_bit224 = add_bits(hash224_field, True) - -pub fn add_bits224( - intermediate: Intermediary, - bytes: ByteArray, -) -> Intermediary { - add_bit224(intermediate, bytes) -} - -const add_i224 = add_int(hash224_field) - -pub fn add_int224( - intermediate: Intermediary, - int: Int, -) -> Intermediary { - add_i224(intermediate, int) -} - -const sub_i224 = sub_int(hash224_field) - -pub fn sub_int224( - intermediate: Intermediary, - int: Int, -) -> Intermediary { - sub_i224(intermediate, int) -} - -const sub_bit224 = sub_bits(hash224_field, True) - -pub fn sub_bits224( - intermediate: Intermediary, - bytes: ByteArray, -) -> Intermediary { - sub_bit224(intermediate, bytes) -} - -const mul_bit224 = mul_bits(hash224_field, True) - -pub fn mul_bits224( - intermediate: Intermediary, - bytes: ByteArray, -) -> Intermediary { - mul_bit224(intermediate, bytes) -} - -const mul_i224 = mul_int(hash224_field) - -pub fn mul_int224( - intermediate: Intermediary, - int: Int, -) -> Intermediary { - mul_i224(intermediate, int) -} - -const neg224 = neg(hash224_field) - -pub fn neg_224(intermediate: Intermediary) -> Intermediary { - neg224(intermediate) -} - -pub fn and_bytes( - left: ByteArray, - right: ByteArray, - extend_shorter: Bool, -) -> ByteArray { - builtin.and_bytearray(extend_shorter, left, right) -} - -pub fn or_bytes( - left: ByteArray, - right: ByteArray, - extend_shorter: Bool, -) -> ByteArray { - builtin.or_bytearray(extend_shorter, left, right) -} - -pub fn xor_bytes( - left: ByteArray, - right: ByteArray, - extend_shorter: Bool, -) -> ByteArray { - builtin.xor_bytearray(extend_shorter, left, right) -} diff --git a/lib/aiken/primitive/bytearray.ak b/lib/aiken/primitive/bytearray.ak index d2f125f..1dc2414 100644 --- a/lib/aiken/primitive/bytearray.ak +++ b/lib/aiken/primitive/bytearray.ak @@ -666,3 +666,15 @@ test starts_with_5() { test starts_with_6() { !starts_with("foo", "foo_") } + +pub fn and_bytes(left: ByteArray, right: ByteArray, pad_end: Bool) -> ByteArray { + builtin.and_bytearray(pad_end, left, right) +} + +pub fn or_bytes(left: ByteArray, right: ByteArray, pad_end: Bool) -> ByteArray { + builtin.or_bytearray(pad_end, left, right) +} + +pub fn xor_bytes(left: ByteArray, right: ByteArray, pad_end: Bool) -> ByteArray { + builtin.xor_bytearray(pad_end, left, right) +} From d490eeadad03b2162b1662f544a9eb268c95b44d Mon Sep 17 00:00:00 2001 From: microproofs Date: Wed, 26 Feb 2025 13:07:57 -0500 Subject: [PATCH 12/16] Add docs and rework library to work for scalar --- lib/aiken/crypto/bitwise.ak | 119 ++++++------ lib/aiken/crypto/bls12_381/g1.ak | 5 +- lib/aiken/crypto/bls12_381/g2.ak | 5 +- lib/aiken/crypto/bls12_381/scalar.ak | 280 ++++++++++++++++----------- lib/aiken/crypto/int224.ak | 132 ++++++++++--- lib/aiken/crypto/int256.ak | 138 ++++++++++--- 6 files changed, 447 insertions(+), 232 deletions(-) diff --git a/lib/aiken/crypto/bitwise.ak b/lib/aiken/crypto/bitwise.ak index 411ab00..8da6da2 100644 --- a/lib/aiken/crypto/bitwise.ak +++ b/lib/aiken/crypto/bitwise.ak @@ -4,129 +4,128 @@ pub opaque type State { inner: Int, } -pub const zero_intermediary = State { inner: 0 } +pub const zero = State { inner: 0 } -pub const one_intermediary = State { inner: 1 } +pub const one = State { inner: 1 } -pub fn add_bits(scalar: Int, big_endian: Bool) { - fn(intermediate: State, bytes: ByteArray) -> State { +pub fn add_bits(field: Int, big_endian: Bool) { + fn(state: State, bytes: ByteArray) -> State { builtin.bytearray_to_integer(big_endian, bytes) - |> builtin.add_integer(intermediate.inner) - |> builtin.mod_integer(scalar) + |> builtin.add_integer(state.inner) + |> builtin.mod_integer(field) |> State } } -pub fn add_int(scalar: Int) { - fn(intermediate: State, int: Int) -> State { - intermediate.inner + int - |> builtin.mod_integer(scalar) +pub fn add_int(field: Int) { + fn(state: State, int: Int) -> State { + state.inner + int + |> builtin.mod_integer(field) |> State } } -pub fn add_intermediary(scalar: Int) { - fn(intermediate: State, other: State) -> State { - intermediate.inner + other.inner - |> builtin.mod_integer(scalar) +pub fn add_state(field: Int) { + fn(state: State, other: State) -> State { + state.inner + other.inner + |> builtin.mod_integer(field) |> State } } -pub fn sub_bits(scalar: Int, big_endian: Bool) { - fn(intermediate: State, bytes: ByteArray) -> State { +pub fn sub_bits(field: Int, big_endian: Bool) { + fn(state: State, bytes: ByteArray) -> State { builtin.bytearray_to_integer(big_endian, bytes) - |> builtin.subtract_integer(intermediate.inner) - |> builtin.mod_integer(scalar) + |> builtin.subtract_integer(state.inner) + |> builtin.mod_integer(field) |> State } } -pub fn sub_int(scalar: Int) { - fn(intermediate: State, int: Int) -> State { - intermediate.inner - int - |> builtin.mod_integer(scalar) +pub fn sub_int(field: Int) { + fn(state: State, int: Int) -> State { + state.inner - int + |> builtin.mod_integer(field) |> State } } -pub fn sub_intermediary(scalar: Int) { - fn(intermediate: State, other: State) -> State { - intermediate.inner - other.inner - |> builtin.mod_integer(scalar) +pub fn sub_state(field: Int) { + fn(state: State, other: State) -> State { + state.inner - other.inner + |> builtin.mod_integer(field) |> State } } -pub fn mul_bits(scalar: Int, big_endian: Bool) { - fn(intermediate: State, bytes: ByteArray) -> State { +pub fn mul_bits(field: Int, big_endian: Bool) { + fn(state: State, bytes: ByteArray) -> State { builtin.bytearray_to_integer(big_endian, bytes) - |> builtin.multiply_integer(intermediate.inner) - |> builtin.mod_integer(scalar) + |> builtin.multiply_integer(state.inner) + |> builtin.mod_integer(field) |> State } } -pub fn mul_int(scalar: Int) { - fn(intermediate: State, int: Int) -> State { - intermediate.inner * int - |> builtin.mod_integer(scalar) +pub fn mul_int(field: Int) { + fn(state: State, int: Int) -> State { + state.inner * int + |> builtin.mod_integer(field) |> State } } -pub fn mul_intermediary(scalar: Int) { - fn(intermediate: State, other: State) -> State { - intermediate.inner * other.inner - |> builtin.mod_integer(scalar) +pub fn mul_state(field: Int) { + fn(state: State, other: State) -> State { + state.inner * other.inner + |> builtin.mod_integer(field) |> State } } -pub fn scale(self: State, e: Int, scalar: Int) -> State { +pub fn scale( + self: State, + e: Int, + mul: fn(State, State) -> State, +) -> State { if e < 0 { - zero_intermediary + zero } else if e == 0 { - one_intermediary + one } else if e % 2 == 0 { - scale(mul_intermediary(scalar)(self, self), e / 2, scalar) + scale(mul(self, self), e / 2, mul) } else { - mul_intermediary(scalar)( - self, - scale(mul_intermediary(scalar)(self, self), ( e - 1 ) / 2, scalar), - ) + 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(scalar: Int) { - fn(self: State, k: Int) -> State { - if k == 0 { - self - } else { - do_scale2(mul_intermediary(scalar)(self, self), k - 1, scalar) - } +pub fn scale2(self: State, k: Int, mul: fn(State, State) -> State) { + if k < 0 { + zero + } else { + do_scale2(self, k, mul) } } -fn do_scale2(self: State, k: Int, scalar) -> State { +fn do_scale2(self: State, k: Int, mul) -> State { if k == 0 { self } else { - do_scale2(mul_intermediary(scalar)(self, self), k - 1, scalar) + do_scale2(mul(self, self), k - 1, mul) } } -pub fn neg(scalar: Int) { - fn(intermediate: State) -> State { - scalar - intermediate.inner +pub fn neg(field: Int) { + fn(state: State) -> State { + ( field - state.inner ) % field |> State } } -pub fn to_int(intermediate: State) -> Int { - intermediate.inner +pub fn to_int(state: State) -> Int { + state.inner } pub fn from_int(int: Int, field: Int) -> State { diff --git a/lib/aiken/crypto/bls12_381/g1.ak b/lib/aiken/crypto/bls12_381/g1.ak index d7b4cc1..2d3c920 100644 --- a/lib/aiken/crypto/bls12_381/g1.ak +++ b/lib/aiken/crypto/bls12_381/g1.ak @@ -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. @@ -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) { 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) } diff --git a/lib/aiken/crypto/bls12_381/g2.ak b/lib/aiken/crypto/bls12_381/g2.ak index 7a2013d..37b8fd4 100644 --- a/lib/aiken/crypto/bls12_381/g2.ak +++ b/lib/aiken/crypto/bls12_381/g2.ak @@ -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. @@ -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) { 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) } diff --git a/lib/aiken/crypto/bls12_381/scalar.ak b/lib/aiken/crypto/bls12_381/scalar.ak index cf028ad..24ef3a8 100644 --- a/lib/aiken/crypto/bls12_381/scalar.ak +++ b/lib/aiken/crypto/bls12_381/scalar.ak @@ -17,136 +17,166 @@ //// Additionally, it includes advanced operations such as exponentiation and calculation of multiplicative inverses, tailored for cryptographic applications. use aiken/builtin +use aiken/crypto/bitwise.{State, one, zero} /// The prime number defining the scalar field of the BLS12-381 curve. pub const field_prime = 52435875175126190479447740508185965837690552500527637822603658699938581184513 -/// Represents the additive identity (zero) in the `Scalar` field. -pub const zero: Scalar = Scalar(0) +pub const field_size = 32 -/// Represents the multiplicative identity (one) in the `Scalar` field. -pub const one: Scalar = Scalar(1) +pub type Scalar = + ByteArray -/// Opaque type representing an element of the finite field `Scalar`. -pub opaque type Scalar { - integer: Int, +test field_prime_1() { + builtin.integer_to_bytearray(True, 32, field_prime) == #"73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001" } // ## Constructing +/// Constructs a new `Scalar` element from a Big-Endian (most-significant bits first) `ByteArray`. +pub fn from_bytes(b: ByteArray) -> State { + b + |> builtin.bytearray_to_integer(True, _) + |> bitwise.from_int(field_prime) +} + +/// Constructs a new `Scalar` element from a Little-Endian (least-significant bits first) `ByteArray`. +pub fn from_bytes_little_endian(bytes: ByteArray) -> State { + bytes + |> builtin.bytearray_to_integer(False, _) + |> bitwise.from_int(field_prime) +} /// Constructs a new `Scalar` element from an integer, ensuring it's within the valid range of the field. -/// Returns `None` if the integer is negative or greater than the prime number defining the field. -pub fn new(n: Int) -> Option { - if n >= 0 && n < field_prime { - Some(Scalar(n)) - } else { - None - } +pub fn from_int(n: Int) -> State { + bitwise.from_int(n, field_prime) } test new_1() { + trace from_int(-1) and { - new(-1) == None, - new(field_prime) == None, - new(834884848) == Some(Scalar(834884848)), + ( from_int(-1) |> to_int ) == field_prime - 1, + ( from_int(field_prime) |> to_int ) == 0, + ( from_int(834884848) |> to_int ) == 834884848, } } -/// Constructs a new `Scalar` element from a Big-Endian (most-significant bits first) `ByteArray`. -pub fn from_bytearray_big_endian(bytes: ByteArray) -> Option { - new(builtin.bytearray_to_integer(True, bytes)) -} - test from_bytearray_big_endian_1() { - from_bytearray_big_endian(#"ffff00") == Some(Scalar(16776960)) -} - -/// Constructs a new `Scalar` element from a Little-Endian (least-significant bits first) `ByteArray`. -pub fn from_bytearray_little_endian(bytes: ByteArray) -> Option { - new(builtin.bytearray_to_integer(False, bytes)) + ( from_bytes(#"ffff00") |> to_int ) == 16776960 } test from_bytearray_little_endian_1() { - from_bytearray_little_endian(#"ffff00") == Some(Scalar(65535)) + ( from_bytes_little_endian(#"ffff00") |> to_int ) == 65535 } +type BitwiseScalarBytes = + fn(State, ByteArray) -> State + +type BitwiseScalarInt = + fn(State, Int) -> State + +type BitwiseScalarState = + fn(State, State) -> State + // ## Modifying /// Exponentiates an `Scalar` element by a non-negative integer exponent, using repeated squaring. /// Note that this function returns `scalar.zero` for negative exponents. /// A dedicated builtin function for this is in the making, see CIP 109. -pub fn scale(self: Scalar, e: Int) -> Scalar { - if e < 0 { - zero - } else if e == 0 { - one - } else if e % 2 == 0 { - scale(mul(self, self), e / 2) - } else { - mul(self, scale(mul(self, self), ( e - 1 ) / 2)) - } +pub fn scale(self: State, e: Int) -> State { + bitwise.scale(self, e, mul) } test scale_1() { + let x = from_int(834884848) + and { - scale(Scalar(834884848), -1) == zero, - scale(Scalar(834884848), 0) == one, - scale(Scalar(834884848), 1) == Scalar(834884848), - scale(Scalar(834884848), 2) == Scalar(697032709419983104), - scale(Scalar(834884848), 3) == Scalar(581942047655130761945608192), - scale(Scalar(field_prime - 4), 200) == Scalar( - 12843927705572658539565969578937286576443167978938369866871449552629978143484, - ), + ( x |> scale(-1) ) == zero, + ( x |> scale(0) ) == one, + ( x |> scale(1) ) == x, + ( x |> scale(2) |> to_int ) == 697032709419983104, + ( x |> scale(3) |> to_int ) == 581942047655130761945608192, + ( + from_int(field_prime - 4) + |> scale(200) + |> to_int + ) == 12843927705572658539565969578937286576443167978938369866871449552629978143484, } } /// 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: Scalar, k: Int) -> Scalar { - if k < 0 { - zero - } else { - do_scale2(self, k) - } -} - -fn do_scale2(self: Scalar, k: Int) -> Scalar { - if k == 0 { - self - } else { - do_scale2(mul(self, self), k - 1) - } +pub fn scale2(self: State, k: Int) -> State { + bitwise.scale2(self, k, mul) } test scale2_1() { + let x = from_int(834884848) + and { - scale2(Scalar(834884848), -1) == zero, - scale2(Scalar(834884848), 0) == scale(Scalar(834884848), 1), - scale2(Scalar(834884848), 1) == scale(Scalar(834884848), 2), - scale2(Scalar(834884848), 2) == scale(Scalar(834884848), 4), - scale2(Scalar(834884848), 3) == scale(Scalar(834884848), 8), - scale2(Scalar(834884848), 4) == scale(Scalar(834884848), 16), + scale2(x, -1) == zero, + scale2(x, 0) == scale(x, 1), + scale2(x, 1) == scale(x, 2), + scale2(x, 2) == scale(x, 4), + scale2(x, 3) == scale(x, 8), + scale2(x, 4) == scale(x, 16), } } // ## Combining +const add_s_scalar: BitwiseScalarState = bitwise.add_state(field_prime) + /// Adds two `Scalar` elements, ensuring the result stays within the finite field range. -pub fn add(left: Scalar, right: Scalar) -> Scalar { - Scalar(( left.integer + right.integer ) % field_prime) +pub fn add(left: State, right: State) -> State { + add_s_scalar(left, right) +} + +const add_bit_scalar: BitwiseScalarBytes = bitwise.add_bits(field_prime, True) + +pub fn add_bytes(intermediate: State, bytes: ByteArray) -> State { + add_bit_scalar(intermediate, bytes) +} + +const add_i_scalar: BitwiseScalarInt = bitwise.add_int(field_prime) + +pub fn add_int(intermediate: State, int: Int) -> State { + add_i_scalar(intermediate, int) } test add_1() { + let x = from_int(834884848) + let y = from_int(field_prime - 1) + let z = from_int(3) + and { - (add(Scalar(834884848), Scalar(834884848)) == Scalar(1669769696))?, - (add(Scalar(field_prime - 1), Scalar(1)) == Scalar(0))?, - (add(Scalar(3), Scalar(field_prime)) == Scalar(3))?, + (( add(x, x) |> to_int ) == 1669769696)?, + (add(y, one) == zero)?, + (add(z, add(y, one)) == z)?, } } /// Divides one `Scalar` element by another, returning `None` if the divisor is zero. -pub fn div(left: Scalar, right: Scalar) -> Option { +pub fn div(left: State, right: State) -> Option> { + if right == zero { + None + } else { + Some(mul(left, scale(right, field_prime - 2))) + } +} + +pub fn div_int(left: State, right: Int) -> Option> { + let right = from_int(right) + if right == zero { + None + } else { + Some(mul(left, scale(right, field_prime - 2))) + } +} + +pub fn div_bytes(left: State, right: ByteArray) -> Option> { + let right = from_bytes(right) + if right == zero { None } else { @@ -155,61 +185,77 @@ pub fn div(left: Scalar, right: Scalar) -> Option { } test div_1() { + let x = from_int(834884848) + and { - div(Scalar(834884848), Scalar(834884848)) == Some(Scalar(1)), - div(Scalar(834884848), zero) == None, - div(Scalar(field_prime - 1), Scalar(2)) == Some( - Scalar( + div(x, x) == Some(one), + div(x, zero) == None, + div(from_int(field_prime - 1), from_int(2)) == Some( + from_int( 26217937587563095239723870254092982918845276250263818911301829349969290592256, ), ), } } +const mul_s_scalar: BitwiseScalarState = bitwise.mul_state(field_prime) + /// Multiplies two `Scalar` elements, with the result constrained within the finite field. -pub fn mul(left: Scalar, right: Scalar) -> Scalar { - Scalar(left.integer * right.integer % field_prime) +pub fn mul(left: State, right: State) -> State { + mul_s_scalar(left, right) +} + +const mul_bit_scalar: BitwiseScalarBytes = bitwise.mul_bits(field_prime, True) + +pub fn mul_bytes(intermediate: State, bytes: ByteArray) -> State { + mul_bit_scalar(intermediate, bytes) +} + +const mul_i_scalar: BitwiseScalarInt = bitwise.mul_int(field_prime) + +pub fn mul_int(intermediate: State, int: Int) -> State { + mul_i_scalar(intermediate, int) } test mul_1() { + let x = from_int(834884848) and { - mul(Scalar(834884848), Scalar(834884848)) == Scalar(697032709419983104), - mul(zero, Scalar(834884848)) == zero, - mul(Scalar(field_prime - 1), Scalar(2)) == Scalar( + mul(x, x) == from_int(697032709419983104), + mul(zero, x) == zero, + mul(from_int(field_prime - 1), from_int(2)) == from_int( 52435875175126190479447740508185965837690552500527637822603658699938581184511, ), } } +const neg_scalar: fn(State) -> State = bitwise.neg(field_prime) + /// Calculates the additive inverse of a `Scalar` element. -pub fn neg(self: Scalar) -> Scalar { - // this is basicly sub(zero, self), but more efficient as it saves one modulo operation - if self.integer == 0 { - self - } else { - Scalar(field_prime - self.integer) - } +pub fn neg(intermediate: State) -> State { + neg_scalar(intermediate) } test neg_1() { + trace neg(zero) + and { - neg(Scalar(834884848)) == Scalar( + neg(from_int(834884848)) == from_int( 52435875175126190479447740508185965837690552500527637822603658699937746299665, ), neg(zero) == zero, - neg(one) == Scalar(field_prime - 1), + neg(one) == from_int(field_prime - 1), } } /// Calculates the multiplicative inverse of an `Scalar` element, returning `None` if the element is zero. -pub fn recip(self: Scalar) -> Option { +pub fn recip(self: State) -> Option> { div(one, self) } test recip_1() { and { - recip(Scalar(834884848)) == Some( - Scalar( + recip(from_int(834884848)) == Some( + from_int( 35891248691642227249400403463796410930702563777316955162085759263735363466421, ), ), @@ -217,39 +263,55 @@ test recip_1() { } } +const sub_s_scalar: BitwiseScalarState = bitwise.sub_state(field_prime) + /// Subtracts one `Scalar` element from another, with the result wrapped within the finite field range. -pub fn sub(left: Scalar, right: Scalar) -> Scalar { - Scalar(( left.integer - right.integer ) % field_prime) +pub fn sub(left: State, right: State) -> State { + sub_s_scalar(left, right) +} + +const sub_bit_scalar: BitwiseScalarBytes = bitwise.sub_bits(field_prime, True) + +pub fn sub_bytes(intermediate: State, bytes: ByteArray) -> State { + sub_bit_scalar(intermediate, bytes) +} + +const sub_i_scalar: BitwiseScalarInt = bitwise.sub_int(field_prime) + +pub fn sub_int(intermediate: State, int: Int) -> State { + sub_i_scalar(intermediate, int) } test sub_1() { + let x = from_int(834884848) + and { - (sub(Scalar(834884848), Scalar(834884848)) == zero)?, - (sub(zero, Scalar(5)) == Scalar(field_prime - 5))?, + (sub(x, x) == zero)?, + (sub(zero, from_int(5)) == from_int(field_prime - 5))?, } } // ## Transforming /// Converts a `Scalar` element back to its integer representation. -pub fn to_int(self: Scalar) -> Int { - self.integer -} - -test to_int_1() { - to_int(Scalar(834884848)) == 834884848 +pub fn to_int(s: State) -> Int { + bitwise.to_int(s) } /// Converts a `Scalar` element to a Big-Endian (most-significant bits first) `ByteArray`. -pub fn to_bytearray_big_endian(self: Scalar, size: Int) -> ByteArray { - builtin.integer_to_bytearray(True, size, self.integer) +pub fn to_bytes(s: State) -> ByteArray { + s |> bitwise.to_int |> builtin.integer_to_bytearray(True, field_size, _) } /// Converts a `Scalar` element to a Little-Endian (least-significant bits first) `ByteArray`. -pub fn to_bytearray_little_endian(self: Scalar, size: Int) -> ByteArray { - builtin.integer_to_bytearray(False, size, self.integer) +pub fn to_bytes_little_endian(s: State) -> ByteArray { + s |> bitwise.to_int |> builtin.integer_to_bytearray(False, field_size, _) +} + +test to_int_1() { + to_int(from_int(834884848)) == 834884848 } test to_bytearray_1() { - to_bytearray_big_endian(Scalar(16777215), 3) == #"ffffff" + ( to_bytes(from_int(16777215)) |> builtin.slice_bytearray(29, 32, _) ) == #"ffffff" } diff --git a/lib/aiken/crypto/int224.ak b/lib/aiken/crypto/int224.ak index 34cf08f..f011b9f 100644 --- a/lib/aiken/crypto/int224.ak +++ b/lib/aiken/crypto/int224.ak @@ -1,32 +1,42 @@ +//// This module implements arithmetic operations in a constrained 224-bit integer field. +//// Operations are performed modulo 2^224, providing a field for cryptographic operations +//// that require 28-byte values. +//// +//// The module provides functionality for basic arithmetic operations (addition, subtraction, +//// multiplication) within this constrained field, as well as conversion functions between +//// different representations. + use aiken/builtin -use aiken/crypto/bitwise.{ - State, add_bits as addbit, add_int as addint, mul_bits as mulbit, - mul_int as mulint, neg as negbit, sub_bits as subbit, sub_int as subint, -} +use aiken/crypto/bitwise.{State} pub type Hash224 = ByteArray +/// The prime defining the 224-bit integer field (2^224) pub const hash224_field = builtin.replicate_byte(28, 0) |> builtin.cons_bytearray(1, _) |> builtin.bytearray_to_integer(True, _) -pub fn to_bytes(intermediate: State) -> ByteArray { - bitwise.to_int(intermediate) - |> builtin.integer_to_bytearray(True, 28, _) -} +pub const field_size = 28 -pub fn to_int(intermediate: State) -> Int { - bitwise.to_int(intermediate) -} +// ## Constructing +/// Constructs a new `Hash224` element from a Big-Endian (most-significant bits first) `ByteArray`. pub fn from_bytes(bytes: Hash224) -> State { bytes |> builtin.bytearray_to_integer(True, _) |> bitwise.from_int(hash224_field) } +/// Constructs a new `Hash224` element from a Little-Endian (least-significant bits first) `ByteArray`. +pub fn from_bytes_little_endian(bytes: ByteArray) -> State { + bytes + |> builtin.bytearray_to_integer(False, _) + |> bitwise.from_int(hash224_field) +} + +/// Constructs a new `Hash224` element from an integer, ensuring it's within the valid range of the field. pub fn from_int(int: Int) -> State { bitwise.from_int(int, hash224_field) } @@ -37,8 +47,35 @@ type Bitwise224Bytes = type Bitwise224Int = fn(State, Int) -> State -const add_bit224: Bitwise224Bytes = addbit(hash224_field, True) +type Bitwise224State = + fn(State, State) -> State + +// ## Modifying + +/// Exponentiates a `Hash224` element by a non-negative integer exponent, using repeated squaring. +/// Note that this function returns `zero` for negative exponents. +pub fn scale(self: State, e: Int) -> State { + bitwise.scale(self, e, 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`. +pub fn scale2(self: State, k: Int) -> State { + bitwise.scale2(self, k, mul) +} + +// ## Combining + +const add_s_hash224: Bitwise224State = bitwise.add_state(hash224_field) +/// Adds two `Hash224` elements, ensuring the result stays within the finite field range. +pub fn add(left: State, right: State) -> State { + add_s_hash224(left, right) +} + +const add_bit224: Bitwise224Bytes = bitwise.add_bits(hash224_field, True) + +/// Adds a ByteArray to a `Hash224` element, interpreting bytes as a big-endian number. pub fn add_bytes( intermediate: State, bytes: ByteArray, @@ -46,29 +83,23 @@ pub fn add_bytes( add_bit224(intermediate, bytes) } -const add_i224: Bitwise224Int = addint(hash224_field) +const add_i224: Bitwise224Int = bitwise.add_int(hash224_field) +/// Adds an integer to a `Hash224` element. pub fn add_int(intermediate: State, int: Int) -> State { add_i224(intermediate, int) } -const sub_i224: Bitwise224Int = subint(hash224_field) +const mul_s_hash224: Bitwise224State = bitwise.mul_state(hash224_field) -pub fn sub_int(intermediate: State, int: Int) -> State { - sub_i224(intermediate, int) -} - -const sub_bit224: Bitwise224Bytes = subbit(hash224_field, True) - -pub fn sub_bytes( - intermediate: State, - bytes: ByteArray, -) -> State { - sub_bit224(intermediate, bytes) +/// Multiplies two `Hash224` elements, with the result constrained within the finite field. +pub fn mul(left: State, right: State) -> State { + mul_s_hash224(left, right) } -const mul_bit224: Bitwise224Bytes = mulbit(hash224_field, True) +const mul_bit224: Bitwise224Bytes = bitwise.mul_bits(hash224_field, True) +/// Multiplies a `Hash224` element by a ByteArray, interpreting bytes as a big-endian number. pub fn mul_bytes( intermediate: State, bytes: ByteArray, @@ -76,14 +107,59 @@ pub fn mul_bytes( mul_bit224(intermediate, bytes) } -const mul_i224: Bitwise224Int = mulint(hash224_field) +const mul_i224: Bitwise224Int = bitwise.mul_int(hash224_field) +/// Multiplies a `Hash224` element by an integer. pub fn mul_int(intermediate: State, int: Int) -> State { mul_i224(intermediate, int) } -const neg224: fn(State) -> State = negbit(hash224_field) +const neg224: fn(State) -> State = bitwise.neg(hash224_field) +/// Calculates the additive inverse of a `Hash224` element. pub fn neg(intermediate: State) -> State { neg224(intermediate) } + +const sub_s_hash224: Bitwise224State = bitwise.sub_state(hash224_field) + +/// Subtracts one `Hash224` element from another, with the result wrapped within the finite field range. +pub fn sub(left: State, right: State) -> State { + sub_s_hash224(left, right) +} + +const sub_bit224: Bitwise224Bytes = bitwise.sub_bits(hash224_field, True) + +/// Subtracts a ByteArray from a `Hash224` element, interpreting bytes as a big-endian number. +pub fn sub_bytes( + intermediate: State, + bytes: ByteArray, +) -> State { + sub_bit224(intermediate, bytes) +} + +const sub_i224: Bitwise224Int = bitwise.sub_int(hash224_field) + +/// Subtracts an integer from a `Hash224` element. +pub fn sub_int(intermediate: State, int: Int) -> State { + sub_i224(intermediate, int) +} + +// ## Transforming + +/// Converts a `Hash224` element back to its integer representation. +pub fn to_int(intermediate: State) -> Int { + bitwise.to_int(intermediate) +} + +/// Converts a `Hash224` element to a Big-Endian (most-significant bits first) `ByteArray`. +pub fn to_bytes(intermediate: State) -> ByteArray { + bitwise.to_int(intermediate) + |> builtin.integer_to_bytearray(True, field_size, _) +} + +/// Converts a `Hash224` element to a Little-Endian (least-significant bits first) `ByteArray`. +pub fn to_bytes_little_endian(intermediate: State) -> ByteArray { + bitwise.to_int(intermediate) + |> builtin.integer_to_bytearray(False, field_size, _) +} diff --git a/lib/aiken/crypto/int256.ak b/lib/aiken/crypto/int256.ak index 40e9117..867bbfe 100644 --- a/lib/aiken/crypto/int256.ak +++ b/lib/aiken/crypto/int256.ak @@ -1,32 +1,42 @@ -use aiken/builtin -use aiken/crypto/bitwise.{ - State, add_bits as addbit, add_int as addint, mul_bits as mulbit, - mul_int as mulint, neg as negbit, sub_bits as subbit, sub_int as subint, -} +//// This module implements arithmetic operations in a constrained 256-bit integer field. +//// Operations are performed modulo 2^256, providing a field for cryptographic operations +//// that require 32-byte values. +//// +//// The module provides functionality for basic arithmetic operations (addition, subtraction, +//// multiplication) within this constrained field, as well as conversion functions between +//// different representations. -pub type Hash256 = - ByteArray +use aiken/builtin +use aiken/crypto/bitwise.{State} +/// The prime defining the 256-bit integer field (2^256) pub const hash256_field = builtin.replicate_byte(32, 0) |> builtin.cons_bytearray(1, _) |> builtin.bytearray_to_integer(True, _) -pub fn to_bytes(intermediate: State) -> ByteArray { - bitwise.to_int(intermediate) - |> builtin.integer_to_bytearray(True, 32, _) -} +pub const field_size = 32 -pub fn to_int(intermediate: State) -> Int { - bitwise.to_int(intermediate) -} +pub type Hash256 = + ByteArray +// ## Constructing + +/// Constructs a new `Hash256` element from a Big-Endian (most-significant bits first) `ByteArray`. pub fn from_bytes(bytes: Hash256) -> State { bytes |> builtin.bytearray_to_integer(True, _) |> bitwise.from_int(hash256_field) } +/// Constructs a new `Hash256` element from a Little-Endian (least-significant bits first) `ByteArray`. +pub fn from_bytes_little_endian(bytes: ByteArray) -> State { + bytes + |> builtin.bytearray_to_integer(False, _) + |> bitwise.from_int(hash256_field) +} + +/// Constructs a new `Hash256` element from an integer, ensuring it's within the valid range of the field. pub fn from_int(int: Int) -> State { bitwise.from_int(int, hash256_field) } @@ -37,8 +47,35 @@ type Bitwise256Bytes = type Bitwise256Int = fn(State, Int) -> State -const add_bit256: Bitwise256Bytes = addbit(hash256_field, True) +type Bitwise256State = + fn(State, State) -> State + +// ## Modifying + +/// Exponentiates a `Hash256` element by a non-negative integer exponent, using repeated squaring. +/// Note that this function returns `zero` for negative exponents. +pub fn scale(self: State, e: Int) -> State { + bitwise.scale(self, e, 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`. +pub fn scale2(self: State, k: Int) -> State { + bitwise.scale2(self, k, mul) +} + +// ## Combining + +const add_s_hash256: Bitwise256State = bitwise.add_state(hash256_field) +/// Adds two `Hash256` elements, ensuring the result stays within the finite field range. +pub fn add(left: State, right: State) -> State { + add_s_hash256(left, right) +} + +const add_bit256: Bitwise256Bytes = bitwise.add_bits(hash256_field, True) + +/// Adds a ByteArray to a `Hash256` element, interpreting bytes as a big-endian number. pub fn add_bytes( intermediate: State, bytes: ByteArray, @@ -46,29 +83,23 @@ pub fn add_bytes( add_bit256(intermediate, bytes) } -const add_i256: Bitwise256Int = addint(hash256_field) +const add_i256: Bitwise256Int = bitwise.add_int(hash256_field) +/// Adds an integer to a `Hash256` element. pub fn add_int(intermediate: State, int: Int) -> State { add_i256(intermediate, int) } -const sub_i256: Bitwise256Int = subint(hash256_field) - -pub fn sub_int(intermediate: State, int: Int) -> State { - sub_i256(intermediate, int) -} - -const sub_bit256: Bitwise256Bytes = subbit(hash256_field, True) +const mul_s_hash256: Bitwise256State = bitwise.mul_state(hash256_field) -pub fn sub_bytes( - intermediate: State, - bytes: ByteArray, -) -> State { - sub_bit256(intermediate, bytes) +/// Multiplies two `Hash256` elements, with the result constrained within the finite field. +pub fn mul(left: State, right: State) -> State { + mul_s_hash256(left, right) } -const mul_bit256: Bitwise256Bytes = mulbit(hash256_field, True) +const mul_bit256: Bitwise256Bytes = bitwise.mul_bits(hash256_field, True) +/// Multiplies a `Hash256` element by a ByteArray, interpreting bytes as a big-endian number. pub fn mul_bytes( intermediate: State, bytes: ByteArray, @@ -76,14 +107,59 @@ pub fn mul_bytes( mul_bit256(intermediate, bytes) } -const mul_i256: Bitwise256Int = mulint(hash256_field) +const mul_i256: Bitwise256Int = bitwise.mul_int(hash256_field) +/// Multiplies a `Hash256` element by an integer. pub fn mul_int(intermediate: State, int: Int) -> State { mul_i256(intermediate, int) } -const neg256: fn(State) -> State = negbit(hash256_field) +const neg256: fn(State) -> State = bitwise.neg(hash256_field) +/// Calculates the additive inverse of a `Hash256` element. pub fn neg(intermediate: State) -> State { neg256(intermediate) } + +const sub_s_hash256: Bitwise256State = bitwise.sub_state(hash256_field) + +/// Subtracts one `Hash256` element from another, with the result wrapped within the finite field range. +pub fn sub(left: State, right: State) -> State { + sub_s_hash256(left, right) +} + +const sub_bit256: Bitwise256Bytes = bitwise.sub_bits(hash256_field, True) + +/// Subtracts a ByteArray from a `Hash256` element, interpreting bytes as a big-endian number. +pub fn sub_bytes( + intermediate: State, + bytes: ByteArray, +) -> State { + sub_bit256(intermediate, bytes) +} + +const sub_i256: Bitwise256Int = bitwise.sub_int(hash256_field) + +/// Subtracts an integer from a `Hash256` element. +pub fn sub_int(intermediate: State, int: Int) -> State { + sub_i256(intermediate, int) +} + +// ## Transforming + +/// Converts a `Hash256` element back to its integer representation. +pub fn to_int(intermediate: State) -> Int { + bitwise.to_int(intermediate) +} + +/// Converts a `Hash256` element to a Big-Endian (most-significant bits first) `ByteArray`. +pub fn to_bytes(intermediate: State) -> ByteArray { + bitwise.to_int(intermediate) + |> builtin.integer_to_bytearray(True, field_size, _) +} + +/// Converts a `Hash256` element to a Little-Endian (least-significant bits first) `ByteArray`. +pub fn to_bytes_little_endian(intermediate: State) -> ByteArray { + bitwise.to_int(intermediate) + |> builtin.integer_to_bytearray(False, field_size, _) +} From 1ce6e3876c2836a143dfd7006a9afa822e88ed95 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sun, 2 Mar 2025 13:28:38 +0100 Subject: [PATCH 13/16] neatpick and iteration over the bitwise API. --- lib/aiken/crypto/bitwise.ak | 2 +- lib/aiken/crypto/int224.ak | 166 +++++++++++++++---------------- lib/aiken/crypto/int256.ak | 159 ++++++++++++++--------------- lib/aiken/crypto/int256.tests.ak | 12 ++- 4 files changed, 160 insertions(+), 179 deletions(-) diff --git a/lib/aiken/crypto/bitwise.ak b/lib/aiken/crypto/bitwise.ak index 8da6da2..4a6183a 100644 --- a/lib/aiken/crypto/bitwise.ak +++ b/lib/aiken/crypto/bitwise.ak @@ -100,7 +100,7 @@ pub fn scale( } /// 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. +/// That is, the exponent $e = 2^k$ for some non-negative integer $k$. Which is used a lot in zk-SNARKs. pub fn scale2(self: State, k: Int, mul: fn(State, State) -> State) { if k < 0 { zero diff --git a/lib/aiken/crypto/int224.ak b/lib/aiken/crypto/int224.ak index f011b9f..8befc41 100644 --- a/lib/aiken/crypto/int224.ak +++ b/lib/aiken/crypto/int224.ak @@ -1,5 +1,5 @@ //// This module implements arithmetic operations in a constrained 224-bit integer field. -//// Operations are performed modulo 2^224, providing a field for cryptographic operations +//// Operations are performed modulo $2^{224}$, providing a field for cryptographic operations //// that require 28-byte values. //// //// The module provides functionality for basic arithmetic operations (addition, subtraction, @@ -7,159 +7,149 @@ //// different representations. use aiken/builtin -use aiken/crypto/bitwise.{State} +use aiken/crypto/bitwise -pub type Hash224 = - ByteArray +pub opaque type Bits224 { + Bits224 +} + +pub type State = + bitwise.State + +type Over = + fn(State, a) -> State -/// The prime defining the 224-bit integer field (2^224) -pub const hash224_field = +/// The prime defining the 224-bit integer field $2^{224}$ +pub const field = builtin.replicate_byte(28, 0) |> builtin.cons_bytearray(1, _) |> builtin.bytearray_to_integer(True, _) +/// The field size, in **bytes**. pub const field_size = 28 // ## Constructing -/// Constructs a new `Hash224` element from a Big-Endian (most-significant bits first) `ByteArray`. -pub fn from_bytes(bytes: Hash224) -> State { +/// Constructs a new `Bits224` element from a Big-Endian (most-significant bits first) `ByteArray`. +pub fn from_bytearray_big_endian(bytes: ByteArray) -> State { bytes |> builtin.bytearray_to_integer(True, _) - |> bitwise.from_int(hash224_field) + |> bitwise.from_int(field) } -/// Constructs a new `Hash224` element from a Little-Endian (least-significant bits first) `ByteArray`. -pub fn from_bytes_little_endian(bytes: ByteArray) -> State { +/// Constructs a new `Bits224` element from a Little-Endian (least-significant bits first) `ByteArray`. +pub fn from_bytearray_little_endian(bytes: ByteArray) -> State { bytes |> builtin.bytearray_to_integer(False, _) - |> bitwise.from_int(hash224_field) + |> bitwise.from_int(field) } -/// Constructs a new `Hash224` element from an integer, ensuring it's within the valid range of the field. -pub fn from_int(int: Int) -> State { - bitwise.from_int(int, hash224_field) +/// Constructs a new `Bits224` element from an integer, ensuring it's within the valid range of the field. +pub fn from_int(int: Int) -> State { + bitwise.from_int(int, field) } -type Bitwise224Bytes = - fn(State, ByteArray) -> State - -type Bitwise224Int = - fn(State, Int) -> State - -type Bitwise224State = - fn(State, State) -> State - // ## Modifying -/// Exponentiates a `Hash224` element by a non-negative integer exponent, using repeated squaring. +/// Exponentiates a `Bits224` element by a non-negative integer exponent, using repeated squaring. /// Note that this function returns `zero` for negative exponents. -pub fn scale(self: State, e: Int) -> State { +pub fn scale(self: State, e: Int) -> State { bitwise.scale(self, e, 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`. -pub fn scale2(self: State, k: Int) -> State { +/// That is, the exponent $e = 2^k$ for some non-negative integer $k$. +pub fn scale2(self: State, k: Int) -> State { bitwise.scale2(self, k, mul) } // ## Combining -const add_s_hash224: Bitwise224State = bitwise.add_state(hash224_field) +const add_s_bits224: Over = bitwise.add_state(field) -/// Adds two `Hash224` elements, ensuring the result stays within the finite field range. -pub fn add(left: State, right: State) -> State { - add_s_hash224(left, right) +/// Adds two `Bits224` elements, ensuring the result stays within the finite field range. +pub fn add(left: State, right: State) -> State { + add_s_bits224(left, right) } -const add_bit224: Bitwise224Bytes = bitwise.add_bits(hash224_field, True) +const add_bit224: Over = bitwise.add_bits(field, True) -/// Adds a ByteArray to a `Hash224` element, interpreting bytes as a big-endian number. -pub fn add_bytes( - intermediate: State, - bytes: ByteArray, -) -> State { - add_bit224(intermediate, bytes) +/// Adds a ByteArray to a `Bits224` element, interpreting bytes as a big-endian number. +pub fn add_bytes(self: State, bytes: ByteArray) -> State { + add_bit224(self, bytes) } -const add_i224: Bitwise224Int = bitwise.add_int(hash224_field) +const add_i224: Over = bitwise.add_int(field) -/// Adds an integer to a `Hash224` element. -pub fn add_int(intermediate: State, int: Int) -> State { - add_i224(intermediate, int) +/// Adds an integer to a `Bits224` element. +pub fn add_int(self: State, int: Int) -> State { + add_i224(self, int) } -const mul_s_hash224: Bitwise224State = bitwise.mul_state(hash224_field) +const mul_s_bits224: Over = bitwise.mul_state(field) -/// Multiplies two `Hash224` elements, with the result constrained within the finite field. -pub fn mul(left: State, right: State) -> State { - mul_s_hash224(left, right) +/// Multiplies two `Bits224` elements, with the result constrained within the finite field. +pub fn mul(left: State, right: State) -> State { + mul_s_bits224(left, right) } -const mul_bit224: Bitwise224Bytes = bitwise.mul_bits(hash224_field, True) +const mul_bit224: Over = bitwise.mul_bits(field, True) -/// Multiplies a `Hash224` element by a ByteArray, interpreting bytes as a big-endian number. -pub fn mul_bytes( - intermediate: State, - bytes: ByteArray, -) -> State { - mul_bit224(intermediate, bytes) +/// Multiplies a `Bits224` element by a ByteArray, interpreting bytes as a big-endian number. +pub fn mul_bytes(self: State, bytes: ByteArray) -> State { + mul_bit224(self, bytes) } -const mul_i224: Bitwise224Int = bitwise.mul_int(hash224_field) +const mul_i224: Over = bitwise.mul_int(field) -/// Multiplies a `Hash224` element by an integer. -pub fn mul_int(intermediate: State, int: Int) -> State { - mul_i224(intermediate, int) +/// Multiplies a `Bits224` element by an integer. +pub fn mul_int(self: State, int: Int) -> State { + mul_i224(self, int) } -const neg224: fn(State) -> State = bitwise.neg(hash224_field) +const neg224: fn(State) -> State = bitwise.neg(field) -/// Calculates the additive inverse of a `Hash224` element. -pub fn neg(intermediate: State) -> State { - neg224(intermediate) +/// Calculates the additive inverse of a `Bits224` element. +pub fn neg(self: State) -> State { + neg224(self) } -const sub_s_hash224: Bitwise224State = bitwise.sub_state(hash224_field) +const sub_s_bits224: Over = bitwise.sub_state(field) -/// Subtracts one `Hash224` element from another, with the result wrapped within the finite field range. -pub fn sub(left: State, right: State) -> State { - sub_s_hash224(left, right) +/// Subtracts one `Bits224` element from another, with the result wrapped within the finite field range. +pub fn sub(left: State, right: State) -> State { + sub_s_bits224(left, right) } -const sub_bit224: Bitwise224Bytes = bitwise.sub_bits(hash224_field, True) +const sub_bit224: Over = bitwise.sub_bits(field, True) -/// Subtracts a ByteArray from a `Hash224` element, interpreting bytes as a big-endian number. -pub fn sub_bytes( - intermediate: State, - bytes: ByteArray, -) -> State { - sub_bit224(intermediate, bytes) +/// Subtracts a `ByteArray` from a `Bits224` element, interpreting bytes as a big-endian number. +pub fn sub_bytes(self: State, bytes: ByteArray) -> State { + sub_bit224(self, bytes) } -const sub_i224: Bitwise224Int = bitwise.sub_int(hash224_field) +const sub_i224: Over = bitwise.sub_int(field) -/// Subtracts an integer from a `Hash224` element. -pub fn sub_int(intermediate: State, int: Int) -> State { - sub_i224(intermediate, int) +/// Subtracts an integer from a `Bits224` element. +pub fn sub_int(self: State, int: Int) -> State { + sub_i224(self, int) } // ## Transforming -/// Converts a `Hash224` element back to its integer representation. -pub fn to_int(intermediate: State) -> Int { - bitwise.to_int(intermediate) -} - -/// Converts a `Hash224` element to a Big-Endian (most-significant bits first) `ByteArray`. -pub fn to_bytes(intermediate: State) -> ByteArray { - bitwise.to_int(intermediate) +/// Converts a `Bits224` element to a Big-Endian (most-significant bits first) `ByteArray`. +pub fn to_bytearray_big_endian(self: State) -> ByteArray { + bitwise.to_int(self) |> builtin.integer_to_bytearray(True, field_size, _) } -/// Converts a `Hash224` element to a Little-Endian (least-significant bits first) `ByteArray`. -pub fn to_bytes_little_endian(intermediate: State) -> ByteArray { - bitwise.to_int(intermediate) +/// Converts a `Bits224` element to a Little-Endian (least-significant bits first) `ByteArray`. +pub fn to_bytearray_little_endian(self: State) -> ByteArray { + bitwise.to_int(self) |> builtin.integer_to_bytearray(False, field_size, _) } + +/// Converts a `Bits224` element back to its integer representation. +pub fn to_int(self: State) -> Int { + bitwise.to_int(self) +} diff --git a/lib/aiken/crypto/int256.ak b/lib/aiken/crypto/int256.ak index 867bbfe..99fe559 100644 --- a/lib/aiken/crypto/int256.ak +++ b/lib/aiken/crypto/int256.ak @@ -1,5 +1,5 @@ //// This module implements arithmetic operations in a constrained 256-bit integer field. -//// Operations are performed modulo 2^256, providing a field for cryptographic operations +//// Operations are performed modulo $2^{256}$, providing a field for cryptographic operations //// that require 32-byte values. //// //// The module provides functionality for basic arithmetic operations (addition, subtraction, @@ -7,159 +7,148 @@ //// different representations. use aiken/builtin -use aiken/crypto/bitwise.{State} +use aiken/crypto/bitwise -/// The prime defining the 256-bit integer field (2^256) -pub const hash256_field = +/// The prime defining the 256-bit integer field $2^{256}$ +pub const field = builtin.replicate_byte(32, 0) |> builtin.cons_bytearray(1, _) |> builtin.bytearray_to_integer(True, _) pub const field_size = 32 -pub type Hash256 = - ByteArray +pub opaque type Bits256 { + Bits256 +} + +pub type State = + bitwise.State + +type Over = + fn(State, a) -> State // ## Constructing -/// Constructs a new `Hash256` element from a Big-Endian (most-significant bits first) `ByteArray`. -pub fn from_bytes(bytes: Hash256) -> State { +/// Constructs a new `Bits256` element from a Big-Endian (most-significant bits first) `ByteArray`. +pub fn from_bytearray_big_endian(bytes: ByteArray) -> State { bytes |> builtin.bytearray_to_integer(True, _) - |> bitwise.from_int(hash256_field) + |> bitwise.from_int(field) } -/// Constructs a new `Hash256` element from a Little-Endian (least-significant bits first) `ByteArray`. -pub fn from_bytes_little_endian(bytes: ByteArray) -> State { +/// Constructs a new `Bits256` element from a Little-Endian (least-significant bits first) `ByteArray`. +pub fn from_bytearray_little_endian(bytes: ByteArray) -> State { bytes |> builtin.bytearray_to_integer(False, _) - |> bitwise.from_int(hash256_field) + |> bitwise.from_int(field) } -/// Constructs a new `Hash256` element from an integer, ensuring it's within the valid range of the field. -pub fn from_int(int: Int) -> State { - bitwise.from_int(int, hash256_field) +/// Constructs a new `Bits256` element from an integer, ensuring it's within the valid range of the field. +pub fn from_int(int: Int) -> State { + bitwise.from_int(int, field) } -type Bitwise256Bytes = - fn(State, ByteArray) -> State - -type Bitwise256Int = - fn(State, Int) -> State - -type Bitwise256State = - fn(State, State) -> State - // ## Modifying -/// Exponentiates a `Hash256` element by a non-negative integer exponent, using repeated squaring. +/// Exponentiates a `Bits256` element by a non-negative integer exponent, using repeated squaring. /// Note that this function returns `zero` for negative exponents. -pub fn scale(self: State, e: Int) -> State { +pub fn scale(self: State, e: Int) -> State { bitwise.scale(self, e, 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`. -pub fn scale2(self: State, k: Int) -> State { +/// That is, the exponent $e = 2^k$ for some non-negative integer $k$. +pub fn scale2(self: State, k: Int) -> State { bitwise.scale2(self, k, mul) } // ## Combining -const add_s_hash256: Bitwise256State = bitwise.add_state(hash256_field) +const add_s_hash256: Over = bitwise.add_state(field) -/// Adds two `Hash256` elements, ensuring the result stays within the finite field range. -pub fn add(left: State, right: State) -> State { +/// Adds two `Bits256` elements, ensuring the result stays within the finite field range. +pub fn add(left: State, right: State) -> State { add_s_hash256(left, right) } -const add_bit256: Bitwise256Bytes = bitwise.add_bits(hash256_field, True) +const add_bit256: Over = bitwise.add_bits(field, True) -/// Adds a ByteArray to a `Hash256` element, interpreting bytes as a big-endian number. -pub fn add_bytes( - intermediate: State, - bytes: ByteArray, -) -> State { - add_bit256(intermediate, bytes) +/// Adds a ByteArray to a `Bits256` element, interpreting bytes as a big-endian number. +pub fn add_bytes(self: State, bytes: ByteArray) -> State { + add_bit256(self, bytes) } -const add_i256: Bitwise256Int = bitwise.add_int(hash256_field) +const add_i256: Over = bitwise.add_int(field) -/// Adds an integer to a `Hash256` element. -pub fn add_int(intermediate: State, int: Int) -> State { - add_i256(intermediate, int) +/// Adds an integer to a `Bits256` element. +pub fn add_int(self: State, int: Int) -> State { + add_i256(self, int) } -const mul_s_hash256: Bitwise256State = bitwise.mul_state(hash256_field) +const mul_s_hash256: Over = bitwise.mul_state(field) -/// Multiplies two `Hash256` elements, with the result constrained within the finite field. -pub fn mul(left: State, right: State) -> State { +/// Multiplies two `Bits256` elements, with the result constrained within the finite field. +pub fn mul(left: State, right: State) -> State { mul_s_hash256(left, right) } -const mul_bit256: Bitwise256Bytes = bitwise.mul_bits(hash256_field, True) +const mul_bit256: Over = bitwise.mul_bits(field, True) -/// Multiplies a `Hash256` element by a ByteArray, interpreting bytes as a big-endian number. -pub fn mul_bytes( - intermediate: State, - bytes: ByteArray, -) -> State { - mul_bit256(intermediate, bytes) +/// Multiplies a `Bits256` element by a ByteArray, interpreting bytes as a big-endian number. +pub fn mul_bytes(self: State, bytes: ByteArray) -> State { + mul_bit256(self, bytes) } -const mul_i256: Bitwise256Int = bitwise.mul_int(hash256_field) +const mul_i256: Over = bitwise.mul_int(field) -/// Multiplies a `Hash256` element by an integer. -pub fn mul_int(intermediate: State, int: Int) -> State { - mul_i256(intermediate, int) +/// Multiplies a `Bits256` element by an integer. +pub fn mul_int(self: State, int: Int) -> State { + mul_i256(self, int) } -const neg256: fn(State) -> State = bitwise.neg(hash256_field) +const neg256: fn(State) -> State = bitwise.neg(field) -/// Calculates the additive inverse of a `Hash256` element. -pub fn neg(intermediate: State) -> State { - neg256(intermediate) +/// Calculates the additive inverse of a `Bits256` element. +pub fn neg(self: State) -> State { + neg256(self) } -const sub_s_hash256: Bitwise256State = bitwise.sub_state(hash256_field) +const sub_s_hash256: Over = bitwise.sub_state(field) -/// Subtracts one `Hash256` element from another, with the result wrapped within the finite field range. -pub fn sub(left: State, right: State) -> State { +/// Subtracts one `Bits256` element from another, with the result wrapped within the finite field range. +pub fn sub(left: State, right: State) -> State { sub_s_hash256(left, right) } -const sub_bit256: Bitwise256Bytes = bitwise.sub_bits(hash256_field, True) +const sub_bit256: Over = bitwise.sub_bits(field, True) -/// Subtracts a ByteArray from a `Hash256` element, interpreting bytes as a big-endian number. -pub fn sub_bytes( - intermediate: State, - bytes: ByteArray, -) -> State { - sub_bit256(intermediate, bytes) +/// Subtracts a `ByteArray` from a `Bits256` element, interpreting bytes as a big-endian number. +pub fn sub_bytes(self: State, bytes: ByteArray) -> State { + sub_bit256(self, bytes) } -const sub_i256: Bitwise256Int = bitwise.sub_int(hash256_field) +const sub_i256: Over = bitwise.sub_int(field) -/// Subtracts an integer from a `Hash256` element. -pub fn sub_int(intermediate: State, int: Int) -> State { - sub_i256(intermediate, int) +/// Subtracts an integer from a `Bits256` element. +pub fn sub_int(self: State, int: Int) -> State { + sub_i256(self, int) } // ## Transforming -/// Converts a `Hash256` element back to its integer representation. -pub fn to_int(intermediate: State) -> Int { - bitwise.to_int(intermediate) -} - -/// Converts a `Hash256` element to a Big-Endian (most-significant bits first) `ByteArray`. -pub fn to_bytes(intermediate: State) -> ByteArray { - bitwise.to_int(intermediate) +/// Converts a `Bits256` element to a Big-Endian (most-significant bits first) `ByteArray`. +pub fn to_bytearray_big_endian(self: State) -> ByteArray { + bitwise.to_int(self) |> builtin.integer_to_bytearray(True, field_size, _) } -/// Converts a `Hash256` element to a Little-Endian (least-significant bits first) `ByteArray`. -pub fn to_bytes_little_endian(intermediate: State) -> ByteArray { - bitwise.to_int(intermediate) +/// Converts a `Bits256` element to a Little-Endian (least-significant bits first) `ByteArray`. +pub fn to_bytearray_little_endian(self: State) -> ByteArray { + bitwise.to_int(self) |> builtin.integer_to_bytearray(False, field_size, _) } + +/// Converts a `Bits256` element back to its integer representation. +pub fn to_int(self: State) -> Int { + bitwise.to_int(self) +} diff --git a/lib/aiken/crypto/int256.tests.ak b/lib/aiken/crypto/int256.tests.ak index 96c3738..b3c1a86 100644 --- a/lib/aiken/crypto/int256.tests.ak +++ b/lib/aiken/crypto/int256.tests.ak @@ -1,4 +1,6 @@ -use aiken/crypto/int256.{add_bytes, from_bytes, to_bytes} +use aiken/crypto/int256.{ + add_bytes, from_bytearray_big_endian, to_bytearray_big_endian, +} test equal_pad_for_addition() { let a: ByteArray = #"acab" @@ -6,9 +8,9 @@ test equal_pad_for_addition() { let x = a - |> from_bytes + |> from_bytearray_big_endian |> add_bytes(b) - |> to_bytes + |> to_bytearray_big_endian x == #"00000000000000000000000000000000000000000000000000000000000177a9" } @@ -19,9 +21,9 @@ test unequal_pad_for_addition() { let x = a - |> from_bytes + |> from_bytearray_big_endian |> add_bytes(b) - |> to_bytes + |> to_bytearray_big_endian x == #"0000000000000000000000000000000000000000000000000000acabbef0c5cc" } From f955733e6d0f825907332740efd5e2ac64885315 Mon Sep 17 00:00:00 2001 From: microproofs Date: Tue, 1 Apr 2025 15:22:10 -0400 Subject: [PATCH 14/16] Adding tests, doing fixes, update version --- aiken.toml | 2 +- lib/aiken/crypto/bitwise.ak | 8 +- lib/aiken/crypto/int224.tests.ak | 360 ++++++++++++++++++++++++ lib/aiken/crypto/int256.tests.ak | 451 +++++++++++++++++++++++-------- 4 files changed, 708 insertions(+), 113 deletions(-) create mode 100644 lib/aiken/crypto/int224.tests.ak diff --git a/aiken.toml b/aiken.toml index 5b312cb..1c11467 100644 --- a/aiken.toml +++ b/aiken.toml @@ -1,6 +1,6 @@ name = "aiken-lang/stdlib" version = "main" -compiler = "v1.1.12" +compiler = "v1.1.15" plutus = "v3" description = "The Aiken Standard Library" diff --git a/lib/aiken/crypto/bitwise.ak b/lib/aiken/crypto/bitwise.ak index 4a6183a..8a5eadb 100644 --- a/lib/aiken/crypto/bitwise.ak +++ b/lib/aiken/crypto/bitwise.ak @@ -1,3 +1,5 @@ +//// @hidden + use aiken/builtin pub opaque type State { @@ -11,7 +13,7 @@ pub const one = State { inner: 1 } pub fn add_bits(field: Int, big_endian: Bool) { fn(state: State, bytes: ByteArray) -> State { builtin.bytearray_to_integer(big_endian, bytes) - |> builtin.add_integer(state.inner) + |> builtin.add_integer(state.inner, _) |> builtin.mod_integer(field) |> State } @@ -36,7 +38,7 @@ pub fn add_state(field: Int) { pub fn sub_bits(field: Int, big_endian: Bool) { fn(state: State, bytes: ByteArray) -> State { builtin.bytearray_to_integer(big_endian, bytes) - |> builtin.subtract_integer(state.inner) + |> builtin.subtract_integer(state.inner, _) |> builtin.mod_integer(field) |> State } @@ -61,7 +63,7 @@ pub fn sub_state(field: Int) { pub fn mul_bits(field: Int, big_endian: Bool) { fn(state: State, bytes: ByteArray) -> State { builtin.bytearray_to_integer(big_endian, bytes) - |> builtin.multiply_integer(state.inner) + |> builtin.multiply_integer(state.inner, _) |> builtin.mod_integer(field) |> State } diff --git a/lib/aiken/crypto/int224.tests.ak b/lib/aiken/crypto/int224.tests.ak new file mode 100644 index 0000000..d8be440 --- /dev/null +++ b/lib/aiken/crypto/int224.tests.ak @@ -0,0 +1,360 @@ +use aiken/builtin +use aiken/crypto/bitwise.{one, zero} +use aiken/crypto/int224.{ + add, add_bytes, add_int, from_bytes, from_bytes_little_endian, from_int, + hash224_field, mul, mul_bytes, mul_int, neg, scale, scale2, sub, sub_bytes, + sub_int, to_bytes, to_bytes_little_endian, to_int, +} + +test equal_pad_for_addition() { + let a: ByteArray = #"acab" + let b: ByteArray = #"cafe" + + let x = + a + |> from_bytes + |> add_bytes(b) + |> to_bytes + + x == #"000000000000000000000000000000000000000000000000000177a9" +} + +test unequal_pad_for_addition() { + let a: ByteArray = #"acabbeefface" + let b: ByteArray = #"cafe" + + let x = + a + |> from_bytes + |> add_bytes(b) + |> to_bytes + + x == #"00000000000000000000000000000000000000000000acabbef0c5cc" +} + +// ## Test for constructing Hash224 elements + +test from_int_1() { + and { + ( from_int(-1) |> to_int ) == hash224_field - 1, + ( from_int(hash224_field) |> to_int ) == 0, + ( from_int(834884848) |> to_int ) == 834884848, + } +} + +test from_bytes_big_endian_1() { + ( from_bytes(#"ffff00") |> to_int ) == 16776960 +} + +test from_bytes_little_endian_1() { + ( from_bytes_little_endian(#"ffff00") |> to_int ) == 65535 +} + +// ## Tests for modifying Hash224 elements + +test scale_1() { + let x = from_int(834884848) + + and { + ( x |> scale(-1) ) == zero, + ( x |> scale(0) ) == one, + ( x |> scale(1) ) == x, + ( x |> scale(2) |> to_int ) == 697032709419983104, + ( x |> scale(3) |> to_int ) == 581942047655130761945608192, + ( + from_int(hash224_field - 5) + |> scale(200) + |> to_int + ) != 0, + } +} + +test scale2_1() { + let a = from_int(2) + + and { + ( scale2(a, 0) |> to_int ) == 2, + ( scale2(a, 1) |> to_int ) == 4, + ( scale2(a, 2) |> to_int ) == 16, + ( scale2(a, 3) |> to_int ) == 256, + } +} + +// ## Tests for combining Hash224 elements + +test add_1() { + let x = from_int(834884848) + let y = from_int(hash224_field - 1) + let z = from_int(3) + + and { + (( add(x, x) |> to_int ) == 1669769696)?, + (add(y, one) == zero)?, + (add(z, add(y, one)) == z)?, + } +} + +test add_overflow_1() { + let a = from_int(hash224_field - 1) + let b = from_int(1) + + ( add(a, b) |> to_int ) == 0 +} + +test mul_1() { + let x = from_int(834884848) + and { + mul(x, x) == from_int(697032709419983104), + mul(zero, x) == zero, + mul(from_int(hash224_field - 1), from_int(2)) == from_int(hash224_field - 2), + } +} + +test neg_1() { + and { + neg(from_int(834884848)) == from_int(hash224_field - 834884848), + neg(zero) == zero, + neg(one) == from_int(hash224_field - 1), + } +} + +test sub_1() { + let x = from_int(834884848) + + and { + (sub(x, x) == zero)?, + (sub(zero, from_int(5)) == from_int(hash224_field - 5))?, + } +} + +// ## Tests for transforming Hash224 elements + +test to_int_1() { + to_int(from_int(834884848)) == 834884848 +} + +test to_bytes_1() { + ( to_bytes(from_int(16777215)) |> builtin.slice_bytearray(25, 28, _) ) == #"ffffff" +} + +test to_bytes_little_endian_1() { + let value = 16777215 + let bytes = to_bytes_little_endian(from_int(value)) + and { + ( bytes |> builtin.slice_bytearray(0, 3, _) ) == #"ffffff", + ( bytes |> builtin.bytearray_to_integer(False, _) ) == value, + } +} + +// ## Tests for various operations and edge cases + +test add_bytes_1() { + let x = from_int(100) + let result = add_bytes(x, #"0a") |> to_int + result == 110 +} + +test add_int_1() { + let x = from_int(100) + let result = add_int(x, 50) |> to_int + result == 150 +} + +test mul_bytes_1() { + let x = from_int(10) + let result = mul_bytes(x, #"0a") |> to_int + result == 100 +} + +test mul_int_1() { + let x = from_int(10) + let result = mul_int(x, 5) |> to_int + result == 50 +} + +test sub_bytes_1() { + let x = from_int(100) + let result = sub_bytes(x, #"0a") |> to_int + result == 90 +} + +test sub_int_1() { + let x = from_int(100) + let result = sub_int(x, 60) |> to_int + result == 40 +} + +test sub_underflow_1() { + let a = from_int(0) + let b = from_int(1) + + ( sub(a, b) |> to_int ) == hash224_field - 1 +} + +test overflow_handling() { + let max = from_int(hash224_field - 1) + and { + (add_int(max, 1) == zero)?, + (( add_int(max, 2) |> to_int ) == 1)?, + } +} + +test wraparound_behavior() { + let x = from_int(10) + let y = from_int(15) + and { + ( sub(x, y) |> to_int ) == hash224_field - 5, + (add(sub(x, y), y) == x)?, + } +} + +test from_bytes_tests() { + let a = #"acabbeefface" + let b = #"cafe" + + and { + ( from_bytes(a) |> to_int ) == 0xacabbeefface, + ( from_bytes(b) |> to_int ) == 0xcafe, + ( from_bytes_little_endian(a) |> to_int ) == 0xcefaefbeabac, + ( from_bytes_little_endian(b) |> to_int ) == 0xfeca, + } +} + +test add_tests() { + let a = from_bytes(#"acab") + let b = from_bytes(#"cafe") + + and { + ( add(a, b) |> to_bytes |> builtin.slice_bytearray(25, 28, _) ) == #"0177a9", + add(from_int(0), from_bytes(#"01")) == from_bytes(#"01"), + } +} + +test add_communitive() { + let a = from_bytes(#"acab") + let b = from_bytes(#"cafe") + + add(a, b) == add(b, a) +} + +test add_associativity() { + let a = from_bytes(#"0101") + let b = from_bytes(#"0202") + let c = from_bytes(#"0303") + + add(add(a, b), c) == add(a, add(b, c)) +} + +test add_identity() { + let a = from_bytes(#"01") + + add(zero, a) == a +} + +test add_bytes_tests() { + let a = from_int(0) + let b = from_bytes(#"acab") + + and { + ( add_bytes(a, #"cafe") |> to_bytes |> builtin.slice_bytearray(26, 28, _) ) == #"cafe", + ( add_bytes(b, #"cafe") |> to_bytes |> builtin.slice_bytearray(25, 28, _) ) == #"0177a9", + } +} + +test sub_tests() { + let a = from_bytes(#"0177a9") + let b = from_bytes(#"cafe") + + and { + ( sub(a, b) |> to_bytes |> builtin.slice_bytearray(26, 28, _) ) == #"acab", + ( + sub(from_bytes(#"77a9"), from_bytes(#"cafe")) + |> to_bytes + |> builtin.slice_bytearray(26, 28, _) + ) == #"acab", + } +} + +test sub_identity() { + let a = from_bytes(#"10") + + sub(a, zero) == a +} + +test mul_tests() { + let a = from_bytes(#"ffff") + let b = from_bytes(#"ffff") + + ( mul(a, b) |> to_bytes |> builtin.slice_bytearray(24, 28, _) ) == #"fffe0001" +} + +test mul_communitive() { + let a = from_bytes(#"acab") + let b = from_bytes(#"cafe") + + mul(a, b) == mul(b, a) +} + +test mul_associativity() { + let a = from_bytes(#"33") + let b = from_bytes(#"44") + let c = from_bytes(#"55") + + mul(mul(a, b), c) == mul(a, mul(b, c)) +} + +test mul_identity() { + let a = from_bytes(#"acab") + + mul(one, a) == a +} + +test mul_bytes_tests() { + let a = from_int(0) + let b = from_bytes(#"0002") + + and { + mul_bytes(a, #"cafe") == zero, + ( mul_bytes(b, #"0003") |> to_bytes |> builtin.slice_bytearray(26, 28, _) ) == #"0006", + } +} + +test bytes_conversion_roundtrip() { + let original = #"acabbeefface" + + and { + ( + to_bytes(from_bytes(original)) + |> builtin.slice_bytearray( + 28 - builtin.length_of_bytearray(original), + 28, + _, + ) + ) == original, + ( + to_bytes_little_endian(from_bytes_little_endian(original)) + |> builtin.slice_bytearray(0, builtin.length_of_bytearray(original), _) + ) == original, + } +} + +test operation_with_zero() { + and { + add(zero, zero) == zero, + mul(zero, from_int(123456)) == zero, + sub(zero, zero) == zero, + neg(zero) == zero, + } +} + +test operation_with_large_numbers() { + let almost_field_size = from_int(hash224_field - 1) + let large_num = from_int(0xffffffffffffffffffffff) + + and { + add(almost_field_size, one) == zero, + mul(large_num, large_num) != zero, + // Should be non-zero due to modular arithmetic + neg(almost_field_size) == one, + } +} diff --git a/lib/aiken/crypto/int256.tests.ak b/lib/aiken/crypto/int256.tests.ak index b3c1a86..45ed67a 100644 --- a/lib/aiken/crypto/int256.tests.ak +++ b/lib/aiken/crypto/int256.tests.ak @@ -1,5 +1,14 @@ +<<<<<<< HEAD use aiken/crypto/int256.{ add_bytes, from_bytearray_big_endian, to_bytearray_big_endian, +======= +use aiken/builtin +use aiken/crypto/bitwise.{one, zero} +use aiken/crypto/int256.{ + add, add_bytes, add_int, from_bytes, from_bytes_little_endian, from_int, + hash256_field, mul, mul_bytes, mul_int, neg, scale, scale2, sub, sub_bytes, + sub_int, to_bytes, to_bytes_little_endian, to_int, +>>>>>>> 8358516 (Adding tests, doing fixes, update version) } test equal_pad_for_addition() { @@ -27,112 +36,336 @@ test unequal_pad_for_addition() { x == #"0000000000000000000000000000000000000000000000000000acabbef0c5cc" } -// test unequal_pad_for_addition1() { -// let a: ByteArray = #"acabbeefface" -// let b: ByteArray = #"cafe" -// let (new_a, new_b) = pad_for_addition(a, b) -// and { -// new_a == #"00acabbeefface", -// new_b == #"0000000000cafe", -// } -// } - -// test unequal_pad_for_addition2() { -// let b: ByteArray = #"acabbeefface" -// let a: ByteArray = #"cafe" -// let (new_a, new_b) = pad_for_addition(a, b) -// and { -// new_a == #"0000000000cafe", -// new_b == #"00acabbeefface", -// } -// } - -// test pad_for_addition_does_works() { -// let b: ByteArray = #"acab" -// let a: ByteArray = #"cafe" -// let (new_a, new_b) = pad_for_addition(a, b) -// and { -// add(a, b) == #"77a9", -// add(new_a, new_b) == #"0177a9", -// } -// } - -// test emptiness_is_empty() { -// add(#"", #"") == #"" -// } - -// test adding_not_equal_length_does_not_work() fail { -// add(#"00", #"acab") == #"acab" -// } - -// test add_communitive() { -// add(#"acab", #"cafe") == add(#"cafe", #"acab") -// } - -// test add_associativity() { -// ( add(#"0101", #"0202") |> add(#"0303") ) == ( -// add(#"0202", #"0303") |> add(#"0101") -// ) -// } - -// test add_identity() { -// add(#"00", #"01") == #"01" -// } - -// test subtracting_does_work1() { -// subtract(#"0177a9", #"00cafe") == #"00acab" -// } - -// test subtracting_does_work2() { -// subtract(#"77a9", #"cafe") == #"acab" -// } - -// test subtracting_not_equal_length_does_not_work() fail { -// subtract(#"0177a9", #"cafe") == #"acab" -// } - -// test subtract_is_not_communitive() fail { -// subtract(#"acab", #"cafe") == add(#"cafe", #"acab") -// } - -// test subtract_identity() { -// subtract(#"10", #"00") == #"10" -// } - -// test equal_pad_for_multiply() { -// let a: ByteArray = #"acab" -// let b: ByteArray = #"cafe" -// let (new_a, new_b) = pad_for_multiply(a, b) -// and { -// new_a == #"0000acab", -// new_b == #"0000cafe", -// } -// } - -// test unequal_pad_for_multiply1() { -// let a: ByteArray = #"acabbeefface" -// let b: ByteArray = #"cafe" -// let (new_a, new_b) = pad_for_multiply(a, b) -// and { -// new_a == #"000000000000acabbeefface", -// new_b == #"00000000000000000000cafe", -// } -// } - -// test unequal_pad_for_multiply2() { -// let b: ByteArray = #"acabbeefface" -// let a: ByteArray = #"cafe" -// let (new_a, new_b) = pad_for_multiply(a, b) -// and { -// new_a == #"00000000000000000000cafe", -// new_b == #"000000000000acabbeefface", -// } -// } - -// test simple_multiply1() { -// multiply(#"0000ffff", #"0000ffff") == #"fffe0001" -// } - -// test multiply_communitive() { -// multiply(#"0000acab", #"0000cafe") == multiply(#"0000cafe", #"0000acab") -// } + +// ## Test for constructing Hash256 elements + +test from_int_1() { + and { + ( from_int(-1) |> to_int ) == hash256_field - 1, + ( from_int(hash256_field) |> to_int ) == 0, + ( from_int(834884848) |> to_int ) == 834884848, + } +} + +test from_bytes_big_endian_1() { + ( from_bytes(#"ffff00") |> to_int ) == 16776960 +} + +test from_bytes_little_endian_1() { + ( from_bytes_little_endian(#"ffff00") |> to_int ) == 65535 +} + +// ## Tests for modifying Hash256 elements + +test scale_1() { + let x = from_int(834884848) + + and { + ( x |> scale(-1) ) == zero, + ( x |> scale(0) ) == one, + ( x |> scale(1) ) == x, + ( x |> scale(2) |> to_int ) == 697032709419983104, + ( x |> scale(3) |> to_int ) == 581942047655130761945608192, + ( + from_int(hash256_field - 5) + |> scale(200) + |> to_int + ) != 0, + } +} + +test scale2_1() { + let a = from_int(2) + + and { + ( scale2(a, 0) |> to_int ) == 2, + ( scale2(a, 1) |> to_int ) == 4, + ( scale2(a, 2) |> to_int ) == 16, + ( scale2(a, 3) |> to_int ) == 256, + } +} + +// ## Tests for combining Hash256 elements + +test add_1() { + let x = from_int(834884848) + let y = from_int(hash256_field - 1) + let z = from_int(3) + + and { + (( add(x, x) |> to_int ) == 1669769696)?, + (add(y, one) == zero)?, + (add(z, add(y, one)) == z)?, + } +} + +test add_overflow_1() { + let a = from_int(hash256_field - 1) + let b = from_int(1) + + ( add(a, b) |> to_int ) == 0 +} + +test mul_1() { + let x = from_int(834884848) + and { + mul(x, x) == from_int(697032709419983104), + mul(zero, x) == zero, + mul(from_int(hash256_field - 1), from_int(2)) == from_int(hash256_field - 2), + } +} + +test neg_1() { + and { + neg(from_int(834884848)) == from_int(hash256_field - 834884848), + neg(zero) == zero, + neg(one) == from_int(hash256_field - 1), + } +} + +test sub_1() { + let x = from_int(834884848) + + and { + (sub(x, x) == zero)?, + (sub(zero, from_int(5)) == from_int(hash256_field - 5))?, + } +} + +// ## Tests for transforming Hash256 elements + +test to_int_1() { + to_int(from_int(834884848)) == 834884848 +} + +test to_bytes_1() { + ( to_bytes(from_int(16777215)) |> builtin.slice_bytearray(29, 32, _) ) == #"ffffff" +} + +test to_bytes_little_endian_1() { + let value = 16777215 + let bytes = to_bytes_little_endian(from_int(value)) + and { + ( bytes |> builtin.slice_bytearray(0, 3, _) ) == #"ffffff", + ( bytes |> builtin.bytearray_to_integer(False, _) ) == value, + } +} + +// ## Tests for various operations and edge cases + +test add_bytes_1() { + let x = from_int(100) + let result = add_bytes(x, #"0a") |> to_int + result == 110 +} + +test add_int_1() { + let x = from_int(100) + let result = add_int(x, 50) |> to_int + result == 150 +} + +test mul_bytes_1() { + let x = from_int(10) + let result = mul_bytes(x, #"0a") |> to_int + result == 100 +} + +test mul_int_1() { + let x = from_int(10) + let result = mul_int(x, 5) |> to_int + result == 50 +} + +test sub_bytes_1() { + let x = from_int(100) + + trace builtin.bytearray_to_integer(True, #"0a") + + let result = sub_bytes(x, #"0a") |> to_int + result == 90 +} + +test sub_int_1() { + let x = from_int(100) + let result = sub_int(x, 60) |> to_int + result == 40 +} + +test sub_underflow_1() { + let a = from_int(0) + let b = from_int(1) + + ( sub(a, b) |> to_int ) == hash256_field - 1 +} + +test overflow_handling() { + let max = from_int(hash256_field - 1) + and { + (add_int(max, 1) == zero)?, + (( add_int(max, 2) |> to_int ) == 1)?, + } +} + +test wraparound_behavior() { + let x = from_int(10) + let y = from_int(15) + and { + ( sub(x, y) |> to_int ) == hash256_field - 5, + (add(sub(x, y), y) == x)?, + } +} + +test from_bytes_tests() { + let a = #"acabbeefface" + let b = #"cafe" + + trace from_bytes_little_endian(a) + trace 0xfaceefbeabac + + and { + ( from_bytes(a) |> to_int ) == 0xacabbeefface, + ( from_bytes(b) |> to_int ) == 0xcafe, + ( from_bytes_little_endian(a) |> to_int ) == 0xcefaefbeabac, + ( from_bytes_little_endian(b) |> to_int ) == 0xfeca, + } +} + +test add_tests() { + let a = from_bytes(#"acab") + let b = from_bytes(#"cafe") + + and { + ( add(a, b) |> to_bytes |> builtin.slice_bytearray(29, 32, _) ) == #"0177a9", + add(from_int(0), from_bytes(#"01")) == from_bytes(#"01"), + } +} + +test add_communitive() { + let a = from_bytes(#"acab") + let b = from_bytes(#"cafe") + + add(a, b) == add(b, a) +} + +test add_associativity() { + let a = from_bytes(#"0101") + let b = from_bytes(#"0202") + let c = from_bytes(#"0303") + + add(add(a, b), c) == add(a, add(b, c)) +} + +test add_identity() { + let a = from_bytes(#"01") + + add(zero, a) == a +} + +test add_bytes_tests() { + let a = from_int(0) + let b = from_bytes(#"acab") + + and { + ( add_bytes(a, #"cafe") |> to_bytes |> builtin.slice_bytearray(30, 32, _) ) == #"cafe", + ( add_bytes(b, #"cafe") |> to_bytes |> builtin.slice_bytearray(29, 32, _) ) == #"0177a9", + } +} + +test sub_tests() { + let a = from_bytes(#"0177a9") + let b = from_bytes(#"cafe") + + and { + ( sub(a, b) |> to_bytes |> builtin.slice_bytearray(30, 32, _) ) == #"acab", + ( + sub(from_bytes(#"77a9"), from_bytes(#"cafe")) + |> to_bytes + |> builtin.slice_bytearray(30, 32, _) + ) == #"acab", + } +} + +test sub_identity() { + let a = from_bytes(#"10") + + sub(a, zero) == a +} + +test mul_tests() { + let a = from_bytes(#"ffff") + let b = from_bytes(#"ffff") + + ( mul(a, b) |> to_bytes |> builtin.slice_bytearray(28, 32, _) ) == #"fffe0001" +} + +test mul_communitive() { + let a = from_bytes(#"acab") + let b = from_bytes(#"cafe") + + mul(a, b) == mul(b, a) +} + +test mul_associativity() { + let a = from_bytes(#"33") + let b = from_bytes(#"44") + let c = from_bytes(#"55") + + mul(mul(a, b), c) == mul(a, mul(b, c)) +} + +test mul_identity() { + let a = from_bytes(#"acab") + + mul(one, a) == a +} + +test mul_bytes_tests() { + let a = from_int(0) + let b = from_bytes(#"0002") + + and { + mul_bytes(a, #"cafe") == zero, + ( mul_bytes(b, #"0003") |> to_bytes |> builtin.slice_bytearray(30, 32, _) ) == #"0006", + } +} + +test bytes_conversion_roundtrip() { + let original = #"acabbeefface" + + and { + ( + to_bytes(from_bytes(original)) + |> builtin.slice_bytearray( + 32 - builtin.length_of_bytearray(original), + 32, + _, + ) + ) == original, + ( + to_bytes_little_endian(from_bytes_little_endian(original)) + |> builtin.slice_bytearray(0, builtin.length_of_bytearray(original), _) + ) == original, + } +} + +test operation_with_zero() { + and { + add(zero, zero) == zero, + mul(zero, from_int(123456)) == zero, + sub(zero, zero) == zero, + neg(zero) == zero, + } +} + +test operation_with_large_numbers() { + let almost_field_size = from_int(hash256_field - 1) + let large_num = from_int(0xffffffffffffffffffffffffffffff) + + and { + add(almost_field_size, one) == zero, + mul(large_num, large_num) != zero, + // Should be non-zero due to modular arithmetic + neg(almost_field_size) == one, + } +} From a11655e9bdb532f1a261c4bcbcfc380a6b6e7998 Mon Sep 17 00:00:00 2001 From: microproofs Date: Tue, 1 Apr 2025 15:42:58 -0400 Subject: [PATCH 15/16] Fix tests --- lib/aiken/crypto/int224.tests.ak | 145 ++++++++++++++++++------------- lib/aiken/crypto/int256.tests.ak | 144 +++++++++++++++++------------- 2 files changed, 167 insertions(+), 122 deletions(-) diff --git a/lib/aiken/crypto/int224.tests.ak b/lib/aiken/crypto/int224.tests.ak index d8be440..5da8054 100644 --- a/lib/aiken/crypto/int224.tests.ak +++ b/lib/aiken/crypto/int224.tests.ak @@ -1,9 +1,10 @@ use aiken/builtin use aiken/crypto/bitwise.{one, zero} use aiken/crypto/int224.{ - add, add_bytes, add_int, from_bytes, from_bytes_little_endian, from_int, - hash224_field, mul, mul_bytes, mul_int, neg, scale, scale2, sub, sub_bytes, - sub_int, to_bytes, to_bytes_little_endian, to_int, + add, add_bytes, add_int, field, from_bytearray_big_endian, + from_bytearray_little_endian, from_int, mul, mul_bytes, mul_int, neg, scale, + scale2, sub, sub_bytes, sub_int, to_bytearray_big_endian, + to_bytearray_little_endian, to_int, } test equal_pad_for_addition() { @@ -12,9 +13,9 @@ test equal_pad_for_addition() { let x = a - |> from_bytes + |> from_bytearray_big_endian |> add_bytes(b) - |> to_bytes + |> to_bytearray_bigg_endian x == #"000000000000000000000000000000000000000000000000000177a9" } @@ -25,9 +26,9 @@ test unequal_pad_for_addition() { let x = a - |> from_bytes + |> from_bytearray_big_endian |> add_bytes(b) - |> to_bytes + |> to_bytearray_big_endian x == #"00000000000000000000000000000000000000000000acabbef0c5cc" } @@ -36,18 +37,18 @@ test unequal_pad_for_addition() { test from_int_1() { and { - ( from_int(-1) |> to_int ) == hash224_field - 1, - ( from_int(hash224_field) |> to_int ) == 0, + ( from_int(-1) |> to_int ) == field - 1, + ( from_int(field) |> to_int ) == 0, ( from_int(834884848) |> to_int ) == 834884848, } } test from_bytes_big_endian_1() { - ( from_bytes(#"ffff00") |> to_int ) == 16776960 + ( from_bytearray_big_endian(#"ffff00") |> to_int ) == 16776960 } test from_bytes_little_endian_1() { - ( from_bytes_little_endian(#"ffff00") |> to_int ) == 65535 + ( from_bytearray_little_endian(#"ffff00") |> to_int ) == 65535 } // ## Tests for modifying Hash224 elements @@ -62,7 +63,7 @@ test scale_1() { ( x |> scale(2) |> to_int ) == 697032709419983104, ( x |> scale(3) |> to_int ) == 581942047655130761945608192, ( - from_int(hash224_field - 5) + from_int(field - 5) |> scale(200) |> to_int ) != 0, @@ -84,7 +85,7 @@ test scale2_1() { test add_1() { let x = from_int(834884848) - let y = from_int(hash224_field - 1) + let y = from_int(field - 1) let z = from_int(3) and { @@ -95,7 +96,7 @@ test add_1() { } test add_overflow_1() { - let a = from_int(hash224_field - 1) + let a = from_int(field - 1) let b = from_int(1) ( add(a, b) |> to_int ) == 0 @@ -106,15 +107,15 @@ test mul_1() { and { mul(x, x) == from_int(697032709419983104), mul(zero, x) == zero, - mul(from_int(hash224_field - 1), from_int(2)) == from_int(hash224_field - 2), + mul(from_int(field - 1), from_int(2)) == from_int(field - 2), } } test neg_1() { and { - neg(from_int(834884848)) == from_int(hash224_field - 834884848), + neg(from_int(834884848)) == from_int(field - 834884848), neg(zero) == zero, - neg(one) == from_int(hash224_field - 1), + neg(one) == from_int(field - 1), } } @@ -123,7 +124,7 @@ test sub_1() { and { (sub(x, x) == zero)?, - (sub(zero, from_int(5)) == from_int(hash224_field - 5))?, + (sub(zero, from_int(5)) == from_int(field - 5))?, } } @@ -134,12 +135,15 @@ test to_int_1() { } test to_bytes_1() { - ( to_bytes(from_int(16777215)) |> builtin.slice_bytearray(25, 28, _) ) == #"ffffff" + ( + to_bytearray_big_endian(from_int(16777215)) + |> builtin.slice_bytearray(25, 28, _) + ) == #"ffffff" } test to_bytes_little_endian_1() { let value = 16777215 - let bytes = to_bytes_little_endian(from_int(value)) + let bytes = to_bytearray_little_endian(from_int(value)) and { ( bytes |> builtin.slice_bytearray(0, 3, _) ) == #"ffffff", ( bytes |> builtin.bytearray_to_integer(False, _) ) == value, @@ -188,11 +192,11 @@ test sub_underflow_1() { let a = from_int(0) let b = from_int(1) - ( sub(a, b) |> to_int ) == hash224_field - 1 + ( sub(a, b) |> to_int ) == field - 1 } test overflow_handling() { - let max = from_int(hash224_field - 1) + let max = from_int(field - 1) and { (add_int(max, 1) == zero)?, (( add_int(max, 2) |> to_int ) == 1)?, @@ -203,7 +207,7 @@ test wraparound_behavior() { let x = from_int(10) let y = from_int(15) and { - ( sub(x, y) |> to_int ) == hash224_field - 5, + ( sub(x, y) |> to_int ) == field - 5, (add(sub(x, y), y) == x)?, } } @@ -213,109 +217,130 @@ test from_bytes_tests() { let b = #"cafe" and { - ( from_bytes(a) |> to_int ) == 0xacabbeefface, - ( from_bytes(b) |> to_int ) == 0xcafe, - ( from_bytes_little_endian(a) |> to_int ) == 0xcefaefbeabac, - ( from_bytes_little_endian(b) |> to_int ) == 0xfeca, + ( from_bytearray_big_endian(a) |> to_int ) == 0xacabbeefface, + ( from_bytearray_big_endian(b) |> to_int ) == 0xcafe, + ( from_bytearray_little_endian(a) |> to_int ) == 0xcefaefbeabac, + ( from_bytearray_little_endian(b) |> to_int ) == 0xfeca, } } test add_tests() { - let a = from_bytes(#"acab") - let b = from_bytes(#"cafe") + let a = from_bytearray_big_endian(#"acab") + let b = from_bytearray_big_endian(#"cafe") and { - ( add(a, b) |> to_bytes |> builtin.slice_bytearray(25, 28, _) ) == #"0177a9", - add(from_int(0), from_bytes(#"01")) == from_bytes(#"01"), + ( + add(a, b) |> to_bytearray_big_endian |> builtin.slice_bytearray(25, 28, _) + ) == #"0177a9", + add(from_int(0), from_bytearray_big_endian(#"01")) == from_bytearray_big_endian( + #"01", + ), } } test add_communitive() { - let a = from_bytes(#"acab") - let b = from_bytes(#"cafe") + let a = from_bytearray_big_endian(#"acab") + let b = from_bytearray_big_endian(#"cafe") add(a, b) == add(b, a) } test add_associativity() { - let a = from_bytes(#"0101") - let b = from_bytes(#"0202") - let c = from_bytes(#"0303") + let a = from_bytearray_big_endian(#"0101") + let b = from_bytearray_big_endian(#"0202") + let c = from_bytearray_big_endian(#"0303") add(add(a, b), c) == add(a, add(b, c)) } test add_identity() { - let a = from_bytes(#"01") + let a = from_bytearray_big_endian(#"01") add(zero, a) == a } test add_bytes_tests() { let a = from_int(0) - let b = from_bytes(#"acab") + let b = from_bytearray_big_endian(#"acab") and { - ( add_bytes(a, #"cafe") |> to_bytes |> builtin.slice_bytearray(26, 28, _) ) == #"cafe", - ( add_bytes(b, #"cafe") |> to_bytes |> builtin.slice_bytearray(25, 28, _) ) == #"0177a9", + ( + add_bytes(a, #"cafe") + |> to_bytearray_big_endian + |> builtin.slice_bytearray(26, 28, _) + ) == #"cafe", + ( + add_bytes(b, #"cafe") + |> to_bytearray_big_endian + |> builtin.slice_bytearray(25, 28, _) + ) == #"0177a9", } } test sub_tests() { - let a = from_bytes(#"0177a9") - let b = from_bytes(#"cafe") + let a = from_bytearray_big_endian(#"0177a9") + let b = from_bytearray_big_endian(#"cafe") and { - ( sub(a, b) |> to_bytes |> builtin.slice_bytearray(26, 28, _) ) == #"acab", ( - sub(from_bytes(#"77a9"), from_bytes(#"cafe")) - |> to_bytes + sub(a, b) |> to_bytearray_big_endian |> builtin.slice_bytearray(26, 28, _) + ) == #"acab", + ( + sub( + from_bytearray_big_endian(#"77a9"), + from_bytearray_big_endian(#"cafe"), + ) + |> to_bytearray_big_endian |> builtin.slice_bytearray(26, 28, _) ) == #"acab", } } test sub_identity() { - let a = from_bytes(#"10") + let a = from_bytearray_big_endian(#"10") sub(a, zero) == a } test mul_tests() { - let a = from_bytes(#"ffff") - let b = from_bytes(#"ffff") + let a = from_bytearray_big_endian(#"ffff") + let b = from_bytearray_big_endian(#"ffff") - ( mul(a, b) |> to_bytes |> builtin.slice_bytearray(24, 28, _) ) == #"fffe0001" + ( mul(a, b) |> to_bytearray_big_endian |> builtin.slice_bytearray(24, 28, _) ) == #"fffe0001" } test mul_communitive() { - let a = from_bytes(#"acab") - let b = from_bytes(#"cafe") + let a = from_bytearray_big_endian(#"acab") + let b = from_bytearray_big_endian(#"cafe") mul(a, b) == mul(b, a) } test mul_associativity() { - let a = from_bytes(#"33") - let b = from_bytes(#"44") - let c = from_bytes(#"55") + let a = from_bytearray_big_endian(#"33") + let b = from_bytearray_big_endian(#"44") + let c = from_bytearray_big_endian(#"55") mul(mul(a, b), c) == mul(a, mul(b, c)) } test mul_identity() { - let a = from_bytes(#"acab") + let a = from_bytearray_big_endian(#"acab") mul(one, a) == a } test mul_bytes_tests() { let a = from_int(0) - let b = from_bytes(#"0002") + let b = from_bytearray_big_endian(#"0002") and { mul_bytes(a, #"cafe") == zero, - ( mul_bytes(b, #"0003") |> to_bytes |> builtin.slice_bytearray(26, 28, _) ) == #"0006", + ( + mul_bytes(b, #"0003") + |> to_bytearray_big_endian + |> builtin.slice_bytearray(26, 28, _) + ) == #"0006", } } @@ -324,7 +349,7 @@ test bytes_conversion_roundtrip() { and { ( - to_bytes(from_bytes(original)) + to_bytearray_big_endian(from_bytearray_big_endian(original)) |> builtin.slice_bytearray( 28 - builtin.length_of_bytearray(original), 28, @@ -332,7 +357,7 @@ test bytes_conversion_roundtrip() { ) ) == original, ( - to_bytes_little_endian(from_bytes_little_endian(original)) + to_bytearray_little_endian(from_bytearray_little_endian(original)) |> builtin.slice_bytearray(0, builtin.length_of_bytearray(original), _) ) == original, } @@ -348,7 +373,7 @@ test operation_with_zero() { } test operation_with_large_numbers() { - let almost_field_size = from_int(hash224_field - 1) + let almost_field_size = from_int(field - 1) let large_num = from_int(0xffffffffffffffffffffff) and { diff --git a/lib/aiken/crypto/int256.tests.ak b/lib/aiken/crypto/int256.tests.ak index 45ed67a..6fe7eb7 100644 --- a/lib/aiken/crypto/int256.tests.ak +++ b/lib/aiken/crypto/int256.tests.ak @@ -1,14 +1,10 @@ -<<<<<<< HEAD -use aiken/crypto/int256.{ - add_bytes, from_bytearray_big_endian, to_bytearray_big_endian, -======= use aiken/builtin use aiken/crypto/bitwise.{one, zero} use aiken/crypto/int256.{ - add, add_bytes, add_int, from_bytes, from_bytes_little_endian, from_int, - hash256_field, mul, mul_bytes, mul_int, neg, scale, scale2, sub, sub_bytes, - sub_int, to_bytes, to_bytes_little_endian, to_int, ->>>>>>> 8358516 (Adding tests, doing fixes, update version) + add, add_bytes, add_int, field, from_bytearray_big_endian, + from_bytearray_little_endian, from_int, mul, mul_bytes, mul_int, neg, scale, + scale2, sub, sub_bytes, sub_int, to_bytearray_big_endian, + to_bytearray_little_endian, to_int, } test equal_pad_for_addition() { @@ -41,18 +37,18 @@ test unequal_pad_for_addition() { test from_int_1() { and { - ( from_int(-1) |> to_int ) == hash256_field - 1, - ( from_int(hash256_field) |> to_int ) == 0, + ( from_int(-1) |> to_int ) == field - 1, + ( from_int(field) |> to_int ) == 0, ( from_int(834884848) |> to_int ) == 834884848, } } test from_bytes_big_endian_1() { - ( from_bytes(#"ffff00") |> to_int ) == 16776960 + ( from_bytearray_big_endian(#"ffff00") |> to_int ) == 16776960 } test from_bytes_little_endian_1() { - ( from_bytes_little_endian(#"ffff00") |> to_int ) == 65535 + ( from_bytearray_little_endian(#"ffff00") |> to_int ) == 65535 } // ## Tests for modifying Hash256 elements @@ -67,7 +63,7 @@ test scale_1() { ( x |> scale(2) |> to_int ) == 697032709419983104, ( x |> scale(3) |> to_int ) == 581942047655130761945608192, ( - from_int(hash256_field - 5) + from_int(field - 5) |> scale(200) |> to_int ) != 0, @@ -89,7 +85,7 @@ test scale2_1() { test add_1() { let x = from_int(834884848) - let y = from_int(hash256_field - 1) + let y = from_int(field - 1) let z = from_int(3) and { @@ -100,7 +96,7 @@ test add_1() { } test add_overflow_1() { - let a = from_int(hash256_field - 1) + let a = from_int(field - 1) let b = from_int(1) ( add(a, b) |> to_int ) == 0 @@ -111,15 +107,15 @@ test mul_1() { and { mul(x, x) == from_int(697032709419983104), mul(zero, x) == zero, - mul(from_int(hash256_field - 1), from_int(2)) == from_int(hash256_field - 2), + mul(from_int(field - 1), from_int(2)) == from_int(field - 2), } } test neg_1() { and { - neg(from_int(834884848)) == from_int(hash256_field - 834884848), + neg(from_int(834884848)) == from_int(field - 834884848), neg(zero) == zero, - neg(one) == from_int(hash256_field - 1), + neg(one) == from_int(field - 1), } } @@ -128,7 +124,7 @@ test sub_1() { and { (sub(x, x) == zero)?, - (sub(zero, from_int(5)) == from_int(hash256_field - 5))?, + (sub(zero, from_int(5)) == from_int(field - 5))?, } } @@ -139,12 +135,15 @@ test to_int_1() { } test to_bytes_1() { - ( to_bytes(from_int(16777215)) |> builtin.slice_bytearray(29, 32, _) ) == #"ffffff" + ( + to_bytearray_big_endian(from_int(16777215)) + |> builtin.slice_bytearray(29, 32, _) + ) == #"ffffff" } test to_bytes_little_endian_1() { let value = 16777215 - let bytes = to_bytes_little_endian(from_int(value)) + let bytes = to_bytearray_little_endian(from_int(value)) and { ( bytes |> builtin.slice_bytearray(0, 3, _) ) == #"ffffff", ( bytes |> builtin.bytearray_to_integer(False, _) ) == value, @@ -196,11 +195,11 @@ test sub_underflow_1() { let a = from_int(0) let b = from_int(1) - ( sub(a, b) |> to_int ) == hash256_field - 1 + ( sub(a, b) |> to_int ) == field - 1 } test overflow_handling() { - let max = from_int(hash256_field - 1) + let max = from_int(field - 1) and { (add_int(max, 1) == zero)?, (( add_int(max, 2) |> to_int ) == 1)?, @@ -211,7 +210,7 @@ test wraparound_behavior() { let x = from_int(10) let y = from_int(15) and { - ( sub(x, y) |> to_int ) == hash256_field - 5, + ( sub(x, y) |> to_int ) == field - 5, (add(sub(x, y), y) == x)?, } } @@ -220,113 +219,134 @@ test from_bytes_tests() { let a = #"acabbeefface" let b = #"cafe" - trace from_bytes_little_endian(a) + trace from_bytearray_little_endian(a) trace 0xfaceefbeabac and { - ( from_bytes(a) |> to_int ) == 0xacabbeefface, - ( from_bytes(b) |> to_int ) == 0xcafe, - ( from_bytes_little_endian(a) |> to_int ) == 0xcefaefbeabac, - ( from_bytes_little_endian(b) |> to_int ) == 0xfeca, + ( from_bytearray_big_endian(a) |> to_int ) == 0xacabbeefface, + ( from_bytearray_big_endian(b) |> to_int ) == 0xcafe, + ( from_bytearray_little_endian(a) |> to_int ) == 0xcefaefbeabac, + ( from_bytearray_little_endian(b) |> to_int ) == 0xfeca, } } test add_tests() { - let a = from_bytes(#"acab") - let b = from_bytes(#"cafe") + let a = from_bytearray_big_endian(#"acab") + let b = from_bytearray_big_endian(#"cafe") and { - ( add(a, b) |> to_bytes |> builtin.slice_bytearray(29, 32, _) ) == #"0177a9", - add(from_int(0), from_bytes(#"01")) == from_bytes(#"01"), + ( + add(a, b) |> to_bytearray_big_endian |> builtin.slice_bytearray(29, 32, _) + ) == #"0177a9", + add(from_int(0), from_bytearray_big_endian(#"01")) == from_bytearray_big_endian( + #"01", + ), } } test add_communitive() { - let a = from_bytes(#"acab") - let b = from_bytes(#"cafe") + let a = from_bytearray_big_endian(#"acab") + let b = from_bytearray_big_endian(#"cafe") add(a, b) == add(b, a) } test add_associativity() { - let a = from_bytes(#"0101") - let b = from_bytes(#"0202") - let c = from_bytes(#"0303") + let a = from_bytearray_big_endian(#"0101") + let b = from_bytearray_big_endian(#"0202") + let c = from_bytearray_big_endian(#"0303") add(add(a, b), c) == add(a, add(b, c)) } test add_identity() { - let a = from_bytes(#"01") + let a = from_bytearray_big_endian(#"01") add(zero, a) == a } test add_bytes_tests() { let a = from_int(0) - let b = from_bytes(#"acab") + let b = from_bytearray_big_endian(#"acab") and { - ( add_bytes(a, #"cafe") |> to_bytes |> builtin.slice_bytearray(30, 32, _) ) == #"cafe", - ( add_bytes(b, #"cafe") |> to_bytes |> builtin.slice_bytearray(29, 32, _) ) == #"0177a9", + ( + add_bytes(a, #"cafe") + |> to_bytearray_big_endian + |> builtin.slice_bytearray(30, 32, _) + ) == #"cafe", + ( + add_bytes(b, #"cafe") + |> to_bytearray_big_endian + |> builtin.slice_bytearray(29, 32, _) + ) == #"0177a9", } } test sub_tests() { - let a = from_bytes(#"0177a9") - let b = from_bytes(#"cafe") + let a = from_bytearray_big_endian(#"0177a9") + let b = from_bytearray_big_endian(#"cafe") and { - ( sub(a, b) |> to_bytes |> builtin.slice_bytearray(30, 32, _) ) == #"acab", ( - sub(from_bytes(#"77a9"), from_bytes(#"cafe")) - |> to_bytes + sub(a, b) |> to_bytearray_big_endian |> builtin.slice_bytearray(30, 32, _) + ) == #"acab", + ( + sub( + from_bytearray_big_endian(#"77a9"), + from_bytearray_big_endian(#"cafe"), + ) + |> to_bytearray_big_endian |> builtin.slice_bytearray(30, 32, _) ) == #"acab", } } test sub_identity() { - let a = from_bytes(#"10") + let a = from_bytearray_big_endian(#"10") sub(a, zero) == a } test mul_tests() { - let a = from_bytes(#"ffff") - let b = from_bytes(#"ffff") + let a = from_bytearray_big_endian(#"ffff") + let b = from_bytearray_big_endian(#"ffff") - ( mul(a, b) |> to_bytes |> builtin.slice_bytearray(28, 32, _) ) == #"fffe0001" + ( mul(a, b) |> to_bytearray_big_endian |> builtin.slice_bytearray(28, 32, _) ) == #"fffe0001" } test mul_communitive() { - let a = from_bytes(#"acab") - let b = from_bytes(#"cafe") + let a = from_bytearray_big_endian(#"acab") + let b = from_bytearray_big_endian(#"cafe") mul(a, b) == mul(b, a) } test mul_associativity() { - let a = from_bytes(#"33") - let b = from_bytes(#"44") - let c = from_bytes(#"55") + let a = from_bytearray_big_endian(#"33") + let b = from_bytearray_big_endian(#"44") + let c = from_bytearray_big_endian(#"55") mul(mul(a, b), c) == mul(a, mul(b, c)) } test mul_identity() { - let a = from_bytes(#"acab") + let a = from_bytearray_big_endian(#"acab") mul(one, a) == a } test mul_bytes_tests() { let a = from_int(0) - let b = from_bytes(#"0002") + let b = from_bytearray_big_endian(#"0002") and { mul_bytes(a, #"cafe") == zero, - ( mul_bytes(b, #"0003") |> to_bytes |> builtin.slice_bytearray(30, 32, _) ) == #"0006", + ( + mul_bytes(b, #"0003") + |> to_bytearray_big_endian + |> builtin.slice_bytearray(30, 32, _) + ) == #"0006", } } @@ -335,7 +355,7 @@ test bytes_conversion_roundtrip() { and { ( - to_bytes(from_bytes(original)) + to_bytearray_big_endian(from_bytearray_big_endian(original)) |> builtin.slice_bytearray( 32 - builtin.length_of_bytearray(original), 32, @@ -343,7 +363,7 @@ test bytes_conversion_roundtrip() { ) ) == original, ( - to_bytes_little_endian(from_bytes_little_endian(original)) + to_bytearray_little_endian(from_bytearray_little_endian(original)) |> builtin.slice_bytearray(0, builtin.length_of_bytearray(original), _) ) == original, } @@ -359,7 +379,7 @@ test operation_with_zero() { } test operation_with_large_numbers() { - let almost_field_size = from_int(hash256_field - 1) + let almost_field_size = from_int(field - 1) let large_num = from_int(0xffffffffffffffffffffffffffffff) and { From 5f82b165f34c238f78812071dacc10a1412f84d2 Mon Sep 17 00:00:00 2001 From: microproofs Date: Tue, 1 Apr 2025 15:45:16 -0400 Subject: [PATCH 16/16] Update continuous integration --- .github/workflows/continuous-integration.yml | 4 ++-- lib/aiken/crypto/int224.tests.ak | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index ca450f0..25ddbf9 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -31,9 +31,9 @@ jobs: uses: actions/configure-pages@v5 - name: 🧰 Install Aiken - uses: aiken-lang/setup-aiken@v1 + uses: aiken-lang/setup-aiken@v1.0.3 with: - version: v1.1.11 + version: v1.1.15 - name: 📝 Run fmt run: aiken fmt --check diff --git a/lib/aiken/crypto/int224.tests.ak b/lib/aiken/crypto/int224.tests.ak index 5da8054..ba31445 100644 --- a/lib/aiken/crypto/int224.tests.ak +++ b/lib/aiken/crypto/int224.tests.ak @@ -15,7 +15,7 @@ test equal_pad_for_addition() { a |> from_bytearray_big_endian |> add_bytes(b) - |> to_bytearray_bigg_endian + |> to_bytearray_big_endian x == #"000000000000000000000000000000000000000000000000000177a9" }