-
Notifications
You must be signed in to change notification settings - Fork 1
Bls12_381 Basic Fp functionality #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ed7b345
e0e7733
ee0fc8a
1b367c4
c081e2c
e08ec14
940cdd6
73436f9
c45a666
fd3d655
744da98
600fa3f
4c0d80e
1fd2716
713c325
a83e6d4
807ff00
83352d5
d372382
5056489
ba82ad7
72066ef
fb794d8
afdb84d
58fe025
78e4c50
720273f
8496a3a
64bb529
ac73088
da30518
20e7a71
e05058d
26ae8d6
4f19992
a029fa1
63b191b
6fcc761
2e03108
82af47b
f447d7e
05e0048
6f95358
a809c69
ec64c62
0f75136
0ef586a
bd4a93e
e30af4c
4d69f81
2bad092
3046b37
300fd42
5ecc807
3f6181c
de6cc51
2076b2f
4504a82
cdf1986
2893b44
e9e4d13
a48e7d0
9e987f9
9df07fb
0b7d36f
f7f4d8b
f3b9c79
beeb298
e999d8c
841f610
1216bca
cc7acbf
52bd896
4b35e1e
4c2acc3
62b1941
ac8906b
a8ee378
5f5d2a1
701da35
7401f18
5a03247
dfe0024
d9242ea
6369569
ac90c31
a1a346e
abf1452
0cb248b
50213dc
11d7039
a7c3cc3
79627b6
070baf7
9d63ca7
94eaae1
f1b365b
743c249
cc3ad80
8ee7924
d235764
eee70db
dfeeea2
8b55d30
9edd86a
6685301
3020dc8
12a762d
45d2a74
0c00ce9
0df4a33
892b827
ae06f20
f65f332
7c755ea
8284a2f
e5bf863
3ffddf1
7e7ee9b
51031ce
a43b441
03f5416
43658ab
25fb487
0145059
3696970
edc32c3
e158f3d
539750c
03ad0ea
e804a32
630a8fa
29e3304
951ab99
6a95611
a8ec3d4
1ddf3b4
9c78652
f2c30ed
125d7e0
6eea130
a08fd73
a96872a
0b74ed1
27e51f7
78fbbd0
6c7ef51
8b61e5d
cd49a80
2c3e6e3
19f1e85
a6eb90b
fde03d2
26f0b8e
1596b90
6c7b479
919fc75
0b9cc5d
d9ca8df
885e1ee
1d3801c
2bfe21b
af824c2
1a117ae
f37ba7f
08ef32f
2d538fc
e63759e
79c36f5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| *.sw linguist-language=Rust |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,3 +8,9 @@ Cargo.lock | |
|
|
||
| # These are backup files generated by rustfmt | ||
| **/*.rs.bk | ||
|
|
||
| */Cargo.lock | ||
| */Forc.lock | ||
|
|
||
| */out/* | ||
| */target/* | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,42 @@ | ||
| # fuel-crypto | ||
| Various Cryptographic Primitives in Sway for the Fuel VM | ||
|
|
||
| # Testing | ||
|
|
||
| ## Spin Up a Fuel node | ||
| From [here](https://fuellabs.github.io/sway/v0.19.0/introduction/overview.html). | ||
| In a separate tab in your terminal, spin up a local Fuel node: | ||
|
|
||
|
|
||
| `fuel-core --db-type in-memory` | ||
|
|
||
| This starts a Fuel node with a volatile database that will be cleared when shut down (good for testing purposes). | ||
|
|
||
| Make sure `fuel-core` is up to date. This can be done with [fuelup](https://github.com/FuelLabs/fuelup). Also, make sure there's only 1 `fuel-core` installed (check this with `which -a fuel-core`). | ||
|
|
||
| ## Edwards25519 | ||
|
|
||
| The testing is done in Rust; the testfiles are in `/test_contract`. See reference in [Sway documentation](https://fuellabs.github.io/sway/v0.17.0/testing/testing-with-rust.html). | ||
|
|
||
| In `main.sw` the contract makes the connection with the library code in edward25519. This in turn can be tested in the `/test_contract/tests` folder. | ||
|
|
||
| To run tests for edwards25519 folder: | ||
| ``` | ||
| cd test_contract | ||
| forc test | ||
| ``` | ||
|
|
||
| ## BLS | ||
|
|
||
| To run tests for bls folder: | ||
| ``` | ||
| cd tests-bls | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Update this |
||
| forc test | ||
| ``` | ||
|
|
||
| ## Running a script | ||
| Also to run a script a Fuel Node has to be spun up. | ||
|
|
||
| ``` | ||
| forc run --unsigned --pretty-print | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| out | ||
| target |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| [project] | ||
| name = "bls12_381" | ||
| version = "0.1.0" | ||
| authors = ["Hashcloak"] | ||
| edition = "2021" | ||
| license = "Apache-2.0" | ||
|
|
||
| [dependencies] | ||
| fuels = { version = "0.23", features = ["fuel-core-lib"] } | ||
| tokio = { version = "1.12", features = ["rt", "macros"] } | ||
|
|
||
| [[test]] | ||
| harness = true | ||
| name = "integration_tests" | ||
| path = "tests/harness.rs" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| [project] | ||
| authors = ["Hashcloak"] | ||
| entry = "lib.sw" | ||
| license = "Apache-2.0" | ||
| name = "bls12_381" | ||
|
|
||
| [dependencies] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,204 @@ | ||
| library choice; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since most of this code is from the Dalek-Cryptography subtle library, we should reproduce the license at the beginning of the file since they released the code under the 3-clause BSD license. |
||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would maybe move this file to a utils folder since having a constant-time boolean implementation will be important for other cryptography primitives that we may implement in sway. |
||
|
|
||
| use core::num::*; | ||
| use std::{option::Option, u128::U128}; | ||
| use core::ops::{Eq, BitwiseAnd, BitwiseOr, BitwiseXor}; | ||
|
|
||
| /////////////// IMPORTANT<start> /////////////// | ||
|
|
||
| // All of this is coming from the dalek cryptograhpy project | ||
| // see https://github.com/dalek-cryptography/subtle/blob/main/src/lib.rs | ||
|
|
||
| /////////////// IMPORTANT<end> /////////////// | ||
|
|
||
| /// The `Choice` struct represents a choice for use in conditional assignment. | ||
| /// | ||
| /// It is a wrapper around a `u8`, which should have the value either `1` (true) | ||
| /// or `0` (false). | ||
| pub struct Choice { c: u8 } | ||
|
|
||
| // Can't use name "From" because of collision with trait in U128 (even though not importing u128::*). | ||
| // This seems to be a bug in Sway, see discussion in Discord https://discord.com/channels/732892373507375164/734213700835082330/1007067117029433405 | ||
| pub trait From { | ||
| fn from(input: u8) -> Self; | ||
| fn into(self) -> u8; | ||
| } | ||
|
|
||
| impl From for Choice { | ||
| fn from(input: u8) -> Self { | ||
| Choice { c: input } | ||
| } | ||
|
|
||
| fn into(self) -> u8 { | ||
| self.c | ||
| } | ||
| } | ||
|
|
||
| // If equals 1u8 => false, if 0u8 => true | ||
| pub fn opposite_choice_value(a: u8) -> bool { | ||
| asm(r1: a, r2) { | ||
| eq r2 r1 zero; | ||
| r2: bool | ||
| } | ||
| } | ||
|
|
||
| impl Choice { | ||
| pub fn unwrap_u8(self) -> u8 { | ||
| self.c | ||
| } | ||
|
|
||
| pub fn unwrap_as_bool(self) -> bool { | ||
| self.c == 1u8 | ||
| } | ||
|
|
||
| pub fn from_bool(b: bool) -> Choice { | ||
| if b { | ||
| Choice{ c: 1u8} | ||
| } else { | ||
| Choice{ c: 0u8} | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Choice { | ||
| pub fn not(self) -> Choice { | ||
| ~Choice::from_bool(opposite_choice_value(self.c)) | ||
| } | ||
| } | ||
|
|
||
| impl BitwiseXor for u8 { | ||
| fn binary_xor(self, other: Self) -> Self { | ||
| asm(r1: self, r2: other, r3) { | ||
| xor r3 r1 r2; | ||
| r3: u8 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl ConditionallySelectable for u8 { | ||
| fn conditional_select(a: u8, b: u8, choice: Choice) -> u32 { | ||
| let mask = wrapping_neg(choice.unwrap_u8()); | ||
| b.binary_xor(mask & (a.binary_xor(b))) | ||
| } | ||
| } | ||
|
|
||
| impl ConditionallySelectable for Choice { | ||
| fn conditional_select(a: Self, b: Self, choice: Choice) -> Self { | ||
| ~Choice::from(~u8::conditional_select(a.c, b.c, choice)) | ||
| } | ||
| } | ||
|
|
||
| impl BitwiseAnd for u8 { | ||
| fn binary_and(self, other: Self) -> Self { | ||
| asm(r1: self, r2: other, r3) { | ||
| and r3 r1 r2; | ||
| r3: u8 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl BitwiseAnd for Choice { | ||
| fn binary_and(self, other: Self) -> Self { | ||
| ~Choice::from(self.c & other.c) | ||
| } | ||
| } | ||
|
|
||
| impl BitwiseOr for u8 { | ||
| fn binary_or(self, other: Self) -> Self { | ||
| asm(r1: self, r2: other, r3) { | ||
| or r3 r1 r2; | ||
| r3: u8 | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl BitwiseOr for Choice { | ||
| fn binary_or(self, other: Self) -> Self { | ||
| ~Choice::from(self.c | other.c) | ||
| } | ||
| } | ||
|
|
||
|
|
||
| /// The `CtOption<T>` type represents an optional value similar to the | ||
| /// [`Option<T>`](core::option::Option) type but is intended for | ||
| /// use in constant time APIs. | ||
|
|
||
| pub struct CtOption<T> { | ||
| value: T, | ||
| is_some: Choice, | ||
| } | ||
|
|
||
| impl<T> CtOption<T> { | ||
| /// This method is used to construct a new `CtOption<T>` and takes | ||
| /// a value of type `T`, and a `Choice` that determines whether | ||
| /// the optional value should be `Some` or not. If `is_some` is | ||
| /// false, the value will still be stored but its value is never | ||
| /// exposed. | ||
| pub fn new(value: T, is_some: Choice) -> CtOption<T> { | ||
| CtOption { | ||
| value: value, | ||
| is_some: is_some, | ||
| } | ||
| } | ||
|
|
||
| pub fn new_from_bool(value: T, is_some: bool) -> CtOption<T> { | ||
| match is_some { | ||
| true => CtOption {value: value, is_some: Choice{ c: 1 },}, | ||
| false => CtOption {value: value, is_some: Choice{ c: 0 },}, | ||
| } | ||
| } | ||
|
|
||
| //To reference `is_some` this would have to go in a separate Impl | ||
| pub fn is_none(self) -> bool { | ||
| !self.is_some.unwrap_as_bool() | ||
| } | ||
|
|
||
| pub fn is_some(self) -> bool { | ||
| self.is_some.unwrap_as_bool() | ||
| } | ||
|
|
||
| pub fn unwrap(self) -> T { | ||
| self.value | ||
| } | ||
|
|
||
| // unwrap_or can't be implemented here.. | ||
| // There is no type restriction possible on generics in Sway | ||
| // See https://discord.com/channels/732892373507375164/734213700835082330/1007097764242522273 | ||
| } | ||
|
|
||
| pub trait ConditionallySelectable { | ||
| // Select a if choice == 1 or select b if choice == 0, in constant time. | ||
| fn conditional_select(a: Self, b: Self, choice: Choice) -> Self; | ||
| } | ||
|
|
||
| // From https://github.com/dalek-cryptography/subtle/blob/main/src/lib.rs | ||
| pub trait ConstantTimeEq { | ||
| fn ct_eq(self, other: Self) -> Choice; | ||
| } | ||
|
|
||
| fn add_wrap_64(a: u64, b :u64) -> u64 { | ||
| let a_128: U128 = ~U128::from(0, a); | ||
| let b_128: U128 = ~U128::from(0, b); | ||
| (a_128 + b_128).lower | ||
| } | ||
|
|
||
| pub fn wrapping_neg(a: u64) -> u64 { | ||
| add_wrap_64(~u64::max() - a, 1) | ||
| } | ||
|
|
||
| impl ConstantTimeEq for u64 { | ||
| fn ct_eq(self, other: u64) -> Choice { | ||
| // comments from reference impl | ||
| // x == 0 if and only if self == other | ||
| let x: u64 = self ^ other; | ||
|
|
||
| // If x == 0, then x and -x are both equal to zero; | ||
| // otherwise, one or both will have its high bit set. | ||
| let y: u64 = (x | wrapping_neg(x)) >> 63; | ||
|
|
||
| // Result is the opposite of the high bit (now shifted to low). | ||
| let res: u8 = y ^ (1u64); | ||
| ~Choice::from(res) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,103 @@ | ||
| library fp12; | ||
|
|
||
| dep fp6; | ||
|
|
||
| use fp6::Fp6; | ||
| use choice::{ConstantTimeEq}; | ||
| use core::ops::{Eq, Add, Subtract, Multiply}; | ||
|
|
||
| pub struct Fp12 { | ||
| c0: Fp6, | ||
| c1: Fp6, | ||
| } | ||
|
|
||
| impl ConditionallySelectable for Fp12 { | ||
| fn conditional_select(a: Self, b: Self, choice: Choice) -> Self { | ||
| Fp12 { | ||
| c0: ~Fp6::conditional_select(a.c0, b.c0, choice), | ||
| c1: ~Fp6::conditional_select(a.c1, b.c1, choice), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl ConstantTimeEq for Fp12 { | ||
| fn ct_eq(self, other: Self) -> Choice { | ||
| self.c0.ct_eq(other.c0) & self.c1.ct_eq(other.c1) | ||
| } | ||
| } | ||
|
|
||
| impl Fp12 { | ||
| fn eq(self, other: Self) -> bool { | ||
| self.ct_eq(other).unwrap_as_bool() | ||
| } | ||
|
|
||
| pub fn zero() -> Self { | ||
| Fp12 { | ||
| c0: ~Fp6::zero(), | ||
| c1: ~Fp6::zero(), | ||
| } | ||
| } | ||
|
|
||
| pub fn one() -> Self { | ||
| Fp12 { | ||
| c0: ~Fp6::one(), | ||
| c1: ~Fp6::zero(), | ||
| } | ||
| } | ||
|
|
||
| fn from(f: Fp) -> Fp12 { | ||
| Fp12 { | ||
| c0: ~Fp6::from(f), | ||
| c1: ~Fp6::zero(), | ||
| } | ||
| } | ||
|
|
||
| fn from(f: Fp2) -> Fp12 { | ||
| Fp12 { | ||
| c0: ~Fp6::from(f), | ||
| c1: ~Fp6::zero(), | ||
| } | ||
| } | ||
|
|
||
| fn from(f: Fp6) -> Fp12 { | ||
| Fp12 { | ||
| c0: f, | ||
| c1: ~Fp6::zero(), | ||
| } | ||
| } | ||
|
|
||
| pub fn is_zero(self) -> Choice { | ||
| self.c0.is_zero().binary_and(self.c1.is_zero()) | ||
| } | ||
|
|
||
| fn neg(self) -> Self { | ||
| Fp12 { | ||
| c0: self.c0.neg(), | ||
| c1: self.c1.neg(), | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Eq for Fp12 { | ||
| fn eq(self, other: Self) -> bool { | ||
| self.eq(other) | ||
| } | ||
| } | ||
|
|
||
| impl Add for Fp12 { | ||
| fn add(self, rhs: Fp12) -> Self { | ||
| Fp12 { | ||
| c0: self.c0 + rhs.c0, | ||
| c1: self.c1 + rhs.c1, | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Subtract for Fp12 { | ||
| fn sub(self, rhs: Fp12) -> Self { | ||
| Fp12 { | ||
| c0: self.c0 - rhs.c0, | ||
| c1: self.c1 - rhs.c1, | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update this