Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add interface for bls12-381 #79

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions lib/aiken/bls12_381/g1.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//// This module is designed for cryptographic operations involving the BLS12-381 elliptic curve, particularly focusing on the G1 group of the curve.
////
//// The key functionalities provided by this module include:
//// - Defining the generator of the G1 group, which is a fixed base point on the elliptic curve used for various cryptographic computations.
//// - Implementing the additive identity (zero) in the G1 group, which plays a crucial role in elliptic curve arithmetic.
//// - Providing functions to compress and decompress points in the G1 group. Compression reduces the size of the point representation, which is useful for efficient storage and transmission. Decompression restores the original point from its compressed form.
//// - Implementing basic arithmetic operations on the points in the G1 group, such as addition and subtraction.
//// - Enabling the exponentiation of a point in the G1 group with a scalar, which is a fundamental operation in elliptic curve cryptography.
//// - Offering a function to hash arbitrary data to a point in the G1 group, a process important in several cryptographic protocols.
////
//// This module ensures that all operations respect the properties of the BLS12-381 curve and the mathematical structure of the G1 group.

use aiken/bls12_381/scalar
use aiken/builtin

/// The compressed generator of the G1 group of the BLS12-381 curve.
/// This constant represents a fixed base point on the elliptic curve.
/// Note that flat encoded plutus does not allow for the direct usage of BLS12-381 points.
/// More explicit, any points in plutus data or scripts must be decompressed before usage onchain.
pub const generator =
perturbing marked this conversation as resolved.
Show resolved Hide resolved
#"97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb"

test generator_1() {
builtin.bls12_381_g1_scalar_mul(
scalar.bls12_381_scalar_field_prime,
decompress(generator),
) == #<Bls12_381, G1>"c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
}

/// Represents the additive identity (zero) in the G1 group.
/// Note that flat encoded plutus does not allow for the direct usage of BLS12-381 points.
/// More explicit, any points in plutus data or scripts must be decompressed before usage onchain.
pub const zero =
#"c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

test zero_1() {
let zero_g1 = decompress(zero)
let g1 = decompress(generator)
and {
zero_g1 == builtin.bls12_381_g1_scalar_mul(
scalar.bls12_381_scalar_field_prime,
g1,
),
zero_g1 == builtin.bls12_381_g1_scalar_mul(
scalar.bls12_381_scalar_field_prime,
#<Bls12_381, G1>"88c7e388ee58f1db9a24d7098b01d13634298bebf2d159254975bd450cb0d287fcc622eb71edde8b469a8513551baf1f",
),
zero_g1 == builtin.bls12_381_g1_scalar_mul(
scalar.bls12_381_scalar_field_prime,
#<Bls12_381, G1>"a6ac32e625dc30b8d31bacf5f4c89c27b0388b15f57ae10de8d5cec02dd1f113c9a31077be05ab587ca57a88d34deb75",
),
}
}

/// Compresses a point in the G1 group into a more compact representation.
/// The compressed representation is a 48-byte string, corresponding to a modified `x` coordinate.
/// The leading most significant 3 bits of this string indicate how to reconstruct the `y` coordinate.
///
/// More explicitly via [Zcash's spec](https://github.com/supranational/blst#serialization-format),
///
/// ```text
/// The most-significant three bits of a G1 or G2 encoding should be masked away before the coordinate(s) are interpreted. These bits are used to unambiguously represent the underlying element:
///
/// - The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form.
/// - The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero.
/// - The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate.
/// ```
pub fn compress(point) {
builtin.bls12_381_g1_compress(point)
}

test compress_1() {
compress(
#<Bls12_381, G1>"97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb",
) == #"97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb"
}

/// Decompresses a point in the G1 group from its compressed form.
pub fn decompress(bytes) {
builtin.bls12_381_g1_uncompress(bytes)
}

test decompress_1() {
let g1 =
#<Bls12_381, G1>"97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb"
decompress(generator) == g1
}

pub fn equal(left, right) {
builtin.bls12_381_g1_equal(left, right)
}

test equal_1() {
let g1 = decompress(generator)
equal(
g1,
#<Bls12_381, G1>"97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb",
)
}

/// Adds two points in the G1 group.
pub fn add(left, right) {
builtin.bls12_381_g1_add(left, right)
}

test add_1() {
let g1 = decompress(generator)
builtin.bls12_381_g1_add(g1, g1) == add(g1, g1)
}

/// Subtracts one point in the G1 group from another.
pub fn sub(left, right) {
builtin.bls12_381_g1_add(left, builtin.bls12_381_g1_neg(right))
}

test sub_1() {
let g1 = decompress(generator)
g1 == sub(add(g1, g1), g1)
}

/// 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.Scalar) {
builtin.bls12_381_g1_scalar_mul(scalar.to_int(e), point)
}

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

/// Hashes arbitrary data to a point in the G1 group.
/// The `dst` parameter is a domain separation tag.
/// You can use this parameter to cryptographically separate different uses of the hash function between applications.
pub fn hash_to_group(bytes, dst) {
builtin.bls12_381_g1_hash_to_group(bytes, dst)
}

test hash_to_group_1() {
hash_to_group("hello", "world") == #<Bls12_381, G1>"89223b03c629cc6bcbbdccbba46b6679bc6a79db82f2d3bd115899a45a5a38c391587b59d3d1e297f977d1c4ee9e3388"
}
144 changes: 144 additions & 0 deletions lib/aiken/bls12_381/g2.ak
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
//// This module is designed for cryptographic operations involving the BLS12-381 elliptic curve, particularly focusing on the G2 group of the curve.
////
//// The key functionalities provided by this module include:
//// - Defining the generator of the G2 group, which is a fixed base point on the elliptic curve used for various cryptographic computations.
//// - Implementing the additive identity (zero) in the G2 group, which plays a crucial role in elliptic curve arithmetic.
//// - Providing functions to compress and decompress points in the G2 group. Compression reduces the size of the point representation, which is useful for efficient storage and transmission. Decompression restores the original point from its compressed form.
//// - Implementing basic arithmetic operations on the points in the G2 group, such as addition and subtraction.
//// - Enabling the exponentiation of a point in the G2 group with a scalar, which is a fundamental operation in elliptic curve cryptography.
//// - Offering a function to hash arbitrary data to a point in the G2 group, a process important in several cryptographic protocols.
////
//// This module ensures that all operations respect the properties of the BLS12-381 curve and the mathematical structure of the G2 group.

use aiken/bls12_381/scalar
use aiken/builtin

/// The compressed generator of the G2 group of the BLS12-381 curve.
/// This constant represents a fixed base point on the elliptic curve.
/// Note that flat encoded plutus does not allow for the direct usage of BLS12-381 points.
/// More explicit, any points in plutus data or scripts must be decompressed before usage onchain.
pub const generator =
#"93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8"

// #<Bls12_381, G2>"93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8"

test generator_1() {
builtin.bls12_381_g2_scalar_mul(
scalar.bls12_381_scalar_field_prime,
decompress(generator),
) == #<Bls12_381, G2>"c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
}

/// Represents the additive identity (zero) in the G2 group.
/// Note that flat encoded plutus does not allow for the direct usage of BLS12-381 points.
/// More explicit, any points in plutus data or scripts must be decompressed before usage onchain.
pub const zero =
#"c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

test zero_1() {
let zero_g2 = decompress(zero)
let g2 = decompress(generator)
and {
zero_g2 == builtin.bls12_381_g2_scalar_mul(
scalar.bls12_381_scalar_field_prime,
g2,
),
zero_g2 == builtin.bls12_381_g2_scalar_mul(
scalar.bls12_381_scalar_field_prime,
#<Bls12_381, G2>"9964a9ac2ee28a4dab595ff0970d446373bf46701c5d0b29ce8e1ba995d811a1c7b193c928269192c64ba1fbe4b1940207c251e086b452b920bc72e3cebab46ce672b9b088ca620a471d3b888d9737f6abd165319aa457dbf8835e3d34196051",
),
zero_g2 == builtin.bls12_381_g2_scalar_mul(
scalar.bls12_381_scalar_field_prime,
#<Bls12_381, G2>"a900e25cb53cf1eeb1a82c0c83292937c49c97966351273767a204256a7ef6e95aa391404387075d361e7b13ccd694db03aa73ee0e1bd2c3dd735582b99fdf71696de72e4eda18ae99ea45995f1c9605aa0057008ee9a4da604b5716fb4a345b",
),
}
}

/// Compresses a point in the G2 group into a more compact representation.
/// The compressed representation is the concatenation of two 48-byte strings, corresponding to a modified and complexified `x` coordinate.
/// The leading most significant 3 bits of this string indicate how to reconstruct the `y` coordinate.
///
/// More explicitly via [Zcash's spec](https://github.com/supranational/blst#serialization-format),
///
/// ```text
/// The most-significant three bits of a G1 or G2 encoding should be masked away before the coordinate(s) are interpreted. These bits are used to unambiguously represent the underlying element:
///
/// - The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form.
/// - The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero.
/// - The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate.
/// ```
pub fn compress(point) {
builtin.bls12_381_g2_compress(point)
}

test compress_1() {
let g2 =
#<Bls12_381, G2>"93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8"
compress(g2) == #"93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8"
}

/// Decompresses a point in the G2 group from its compressed form.
pub fn decompress(bytes) {
builtin.bls12_381_g2_uncompress(bytes)
}

test decompress_1() {
let g2 =
#<Bls12_381, G2>"93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8"
decompress(generator) == g2
}

pub fn equal(left, right) {
builtin.bls12_381_g2_equal(left, right)
}

test equal_1() {
let g2 = decompress(generator)
equal(
g2,
#<Bls12_381, G2>"93e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8",
)
}

/// Adds two points in the G2 group.
pub fn add(left, right) {
builtin.bls12_381_g2_add(left, right)
}

test add_1() {
let g2 = decompress(generator)
builtin.bls12_381_g2_add(g2, g2) == add(g2, g2)
}

/// Subtracts one point in the G2 group from another.
pub fn sub(left, right) {
builtin.bls12_381_g2_add(left, builtin.bls12_381_g2_neg(right))
}

test sub_1() {
let g2 = decompress(generator)
g2 == sub(add(g2, g2), g2)
}

/// 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.Scalar) {
builtin.bls12_381_g2_scalar_mul(scalar.to_int(e), point)
}

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

/// Hashes arbitrary data to a point in the G2 group.
/// The `dst` parameter is a domain separation tag.
/// You can use this parameter to cryptographically separate different uses of the hash function between applications.
pub fn hash_to_group(bytes, dst) {
builtin.bls12_381_g2_hash_to_group(bytes, dst)
}

test hash_to_group_1() {
hash_to_group("hello", "world") == #<Bls12_381, G2>"a18486bba1dc8321f4998ed4268c6df8dfa5618dd5c91595844059d517f8104bf8031d3e766f9c99db1d6f58b201ee9614de92fc08f9e5cc3a6cd814e871857cb6e3924e8a4fa48775116c5f158d58ceda63614d62f6b7bc47db798d656969a5"
}
Loading