crypto_algebra - [mainnet]
This module provides generic structs/functions for operations of algebraic structures (e.g. fields and groups), which can be used to build generic cryptographic schemes atop. E.g., a Groth16 ZK proof verifier can be built to work over any pairing supported in this module.
In general, every structure implements basic operations like (de)serialization, equality check, random sampling.
A group may also implement the following operations. (Additive group notation is assumed.)
order()
for getting the group order.zero()
for getting the group identity.one()
for getting the group generator (if exists).neg()
for group element inversion.add()
for group operation (i.e., a group addition).sub()
for group element subtraction.double()
for efficient doubling.scalar_mul()
for group scalar multiplication.multi_scalar_mul()
for efficient group multi-scalar multiplication.hash_to()
for hash-to-group.
A field may also implement the following operations.
zero()
for getting the field additive identity.one()
for getting the field multiplicative identity.add()
for field addition.sub()
for field subtraction.mul()
for field multiplication.div()
for field division.neg()
for field negation.inv()
for field inversion.sqr()
for efficient field element squaring.from_u64()
for quick conversion from u64 to field element.
For 3 groups that admit a bilinear map, pairing()
and multi_pairing()
may be implemented.
For a subset/superset relationship between 2 structures, upcast()
and downcast()
may be implemented.
E.g., in BLS12-381 pairing, since Gt
is a subset of Fq12
,
upcast<Gt, Fq12>()
and downcast<Fq12, Gt>()
will be supported.
See *_algebra.move
for currently implemented algebraic structures.
use 0x1::error;use 0x1::features;use 0x1::option;
Constants
const E_NON_EQUAL_LENGTHS: u64 = 2;
const E_NOT_IMPLEMENTED: u64 = 1;
const E_TOO_MUCH_MEMORY_USED: u64 = 3;
Structs
Element
This struct represents an element of a structure S
.
struct Element<S> has copy, drop
Fields
-
handle: u64
Functions
eq
Check if x == y
for elements x
and y
of a structure S
.
public fun eq<S>(x: &crypto_algebra::Element<S>, y: &crypto_algebra::Element<S>): bool
Implementation
public fun eq<S>(x: &Element<S>, y: &Element<S>): bool { abort_unless_cryptography_algebra_natives_enabled(); eq_internal<S>(x.handle, y.handle)}
from_u64
Convert a u64 to an element of a structure S
.
public fun from_u64<S>(value: u64): crypto_algebra::Element<S>
Implementation
public fun from_u64<S>(value: u64): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element<S> { handle: from_u64_internal<S>(value) }}
zero
Return the additive identity of field S
, or the identity of group S
.
public fun zero<S>(): crypto_algebra::Element<S>
Implementation
public fun zero<S>(): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element<S> { handle: zero_internal<S>() }}
one
Return the multiplicative identity of field S
, or a fixed generator of group S
.
public fun one<S>(): crypto_algebra::Element<S>
Implementation
public fun one<S>(): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element<S> { handle: one_internal<S>() }}
neg
Compute -x
for an element x
of a structure S
.
public fun neg<S>(x: &crypto_algebra::Element<S>): crypto_algebra::Element<S>
Implementation
public fun neg<S>(x: &Element<S>): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element<S> { handle: neg_internal<S>(x.handle) }}
add
Compute x + y
for elements x
and y
of structure S
.
public fun add<S>(x: &crypto_algebra::Element<S>, y: &crypto_algebra::Element<S>): crypto_algebra::Element<S>
Implementation
public fun add<S>(x: &Element<S>, y: &Element<S>): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element<S> { handle: add_internal<S>(x.handle, y.handle) }}
sub
Compute x - y
for elements x
and y
of a structure S
.
public fun sub<S>(x: &crypto_algebra::Element<S>, y: &crypto_algebra::Element<S>): crypto_algebra::Element<S>
Implementation
public fun sub<S>(x: &Element<S>, y: &Element<S>): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element<S> { handle: sub_internal<S>(x.handle, y.handle) }}
mul
Compute x * y
for elements x
and y
of a structure S
.
public fun mul<S>(x: &crypto_algebra::Element<S>, y: &crypto_algebra::Element<S>): crypto_algebra::Element<S>
Implementation
public fun mul<S>(x: &Element<S>, y: &Element<S>): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element<S> { handle: mul_internal<S>(x.handle, y.handle) }}
div
Try computing x / y
for elements x
and y
of a structure S
.
Return none if y
does not have a multiplicative inverse in the structure S
(e.g., when S
is a field, and y
is zero).
public fun div<S>(x: &crypto_algebra::Element<S>, y: &crypto_algebra::Element<S>): option::Option<crypto_algebra::Element<S>>
Implementation
public fun div<S>(x: &Element<S>, y: &Element<S>): Option<Element<S>> { abort_unless_cryptography_algebra_natives_enabled(); let (succ, handle) = div_internal<S>(x.handle, y.handle); if (succ) { some(Element<S> { handle }) } else { none() }}
sqr
Compute x^2
for an element x
of a structure S
. Faster and cheaper than mul(x, x)
.
public fun sqr<S>(x: &crypto_algebra::Element<S>): crypto_algebra::Element<S>
Implementation
public fun sqr<S>(x: &Element<S>): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element<S> { handle: sqr_internal<S>(x.handle) }}
inv
Try computing x^(-1)
for an element x
of a structure S
.
Return none if x
does not have a multiplicative inverse in the structure S
(e.g., when S
is a field, and x
is zero).
public fun inv<S>(x: &crypto_algebra::Element<S>): option::Option<crypto_algebra::Element<S>>
Implementation
public fun inv<S>(x: &Element<S>): Option<Element<S>> { abort_unless_cryptography_algebra_natives_enabled(); let (succeeded, handle) = inv_internal<S>(x.handle); if (succeeded) { let scalar = Element<S> { handle }; some(scalar) } else { none() }}
double
Compute 2*P
for an element P
of a structure S
. Faster and cheaper than add(P, P)
.
public fun double<S>(element_p: &crypto_algebra::Element<S>): crypto_algebra::Element<S>
Implementation
public fun double<S>(element_p: &Element<S>): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element<S> { handle: double_internal<S>(element_p.handle) }}
multi_scalar_mul
Compute k[0]*P[0]+…+k[n-1]*P[n-1]
, where
P[]
are n
elements of group G
represented by parameter elements
, and
k[]
are n
elements of the scalarfield S
of group G
represented by parameter scalars
.
Abort with code std::error::invalid_argument(E_NON_EQUAL_LENGTHS)
if the sizes of elements
and scalars
do not match.
public fun multi_scalar_mul<G, S>(elements: &vector<crypto_algebra::Element<G>>, scalars: &vector<crypto_algebra::Element<S>>): crypto_algebra::Element<G>
Implementation
public fun multi_scalar_mul<G, S>(elements: &vector<Element<G>>, scalars: &vector<Element<S>>): Element<G> { let element_handles = handles_from_elements(elements); let scalar_handles = handles_from_elements(scalars); Element<G> { handle: multi_scalar_mul_internal<G, S>(element_handles, scalar_handles) }}
scalar_mul
Compute k*P
, where P
is an element of a group G
and k
is an element of the scalar field S
associated to the group G
.
public fun scalar_mul<G, S>(element_p: &crypto_algebra::Element<G>, scalar_k: &crypto_algebra::Element<S>): crypto_algebra::Element<G>
Implementation
public fun scalar_mul<G, S>(element_p: &Element<G>, scalar_k: &Element<S>): Element<G> { abort_unless_cryptography_algebra_natives_enabled(); Element<G> { handle: scalar_mul_internal<G, S>(element_p.handle, scalar_k.handle) }}
multi_pairing
Efficiently compute e(P[0],Q[0])+…+e(P[n-1],Q[n-1])
,
where e: (G1,G2) -> (Gt)
is the pairing function from groups (G1,G2)
to group Gt
,
P[]
are n
elements of group G1
represented by parameter g1_elements
, and
Q[]
are n
elements of group G2
represented by parameter g2_elements
.
Abort with code std::error::invalid_argument(E_NON_EQUAL_LENGTHS)
if the sizes of g1_elements
and g2_elements
do not match.
NOTE: we are viewing the target group Gt
of the pairing as an additive group,
rather than a multiplicative one (which is typically the case).
public fun multi_pairing<G1, G2, Gt>(g1_elements: &vector<crypto_algebra::Element<G1>>, g2_elements: &vector<crypto_algebra::Element<G2>>): crypto_algebra::Element<Gt>
Implementation
public fun multi_pairing<G1,G2,Gt>(g1_elements: &vector<Element<G1>>, g2_elements: &vector<Element<G2>>): Element<Gt> { abort_unless_cryptography_algebra_natives_enabled(); let g1_handles = handles_from_elements(g1_elements); let g2_handles = handles_from_elements(g2_elements); Element<Gt> { handle: multi_pairing_internal<G1,G2,Gt>(g1_handles, g2_handles) }}
pairing
Compute the pairing function (a.k.a., bilinear map) on a G1
element and a G2
element.
Return an element in the target group Gt
.
public fun pairing<G1, G2, Gt>(element_1: &crypto_algebra::Element<G1>, element_2: &crypto_algebra::Element<G2>): crypto_algebra::Element<Gt>
Implementation
public fun pairing<G1,G2,Gt>(element_1: &Element<G1>, element_2: &Element<G2>): Element<Gt> { abort_unless_cryptography_algebra_natives_enabled(); Element<Gt> { handle: pairing_internal<G1,G2,Gt>(element_1.handle, element_2.handle) }}
deserialize
Try deserializing a byte array to an element of an algebraic structure S
using a given serialization format F
.
Return none if the deserialization failed.
public fun deserialize<S, F>(bytes: &vector<u8>): option::Option<crypto_algebra::Element<S>>
Implementation
public fun deserialize<S, F>(bytes: &vector<u8>): Option<Element<S>> { abort_unless_cryptography_algebra_natives_enabled(); let (succeeded, handle) = deserialize_internal<S, F>(bytes); if (succeeded) { some(Element<S> { handle }) } else { none() }}
serialize
Serialize an element of an algebraic structure S
to a byte array using a given serialization format F
.
public fun serialize<S, F>(element: &crypto_algebra::Element<S>): vector<u8>
Implementation
public fun serialize<S, F>(element: &Element<S>): vector<u8> { abort_unless_cryptography_algebra_natives_enabled(); serialize_internal<S, F>(element.handle)}
order
Get the order of structure S
, a big integer little-endian encoded as a byte array.
public fun order<S>(): vector<u8>
Implementation
public fun order<S>(): vector<u8> { abort_unless_cryptography_algebra_natives_enabled(); order_internal<S>()}
upcast
Cast an element of a structure S
to a parent structure L
.
public fun upcast<S, L>(element: &crypto_algebra::Element<S>): crypto_algebra::Element<L>
Implementation
public fun upcast<S,L>(element: &Element<S>): Element<L> { abort_unless_cryptography_algebra_natives_enabled(); Element<L> { handle: upcast_internal<S,L>(element.handle) }}
downcast
Try casting an element x
of a structure L
to a sub-structure S
.
Return none if x
is not a member of S
.
NOTE: Membership check in S
is performed inside, which can be expensive, depending on the structures L
and S
.
public fun downcast<L, S>(element_x: &crypto_algebra::Element<L>): option::Option<crypto_algebra::Element<S>>
Implementation
public fun downcast<L,S>(element_x: &Element<L>): Option<Element<S>> { abort_unless_cryptography_algebra_natives_enabled(); let (succ, new_handle) = downcast_internal<L,S>(element_x.handle); if (succ) { some(Element<S> { handle: new_handle }) } else { none() }}
hash_to
Hash an arbitrary-length byte array msg
into structure S
with a domain separation tag dst
using the given hash-to-structure suite H
.
NOTE: some hashing methods do not accept a dst
and will abort if a non-empty one is provided.
public fun hash_to<S, H>(dst: &vector<u8>, msg: &vector<u8>): crypto_algebra::Element<S>
Implementation
public fun hash_to<S, H>(dst: &vector<u8>, msg: &vector<u8>): Element<S> { abort_unless_cryptography_algebra_natives_enabled(); Element { handle: hash_to_internal<S, H>(dst, msg) }}
abort_unless_cryptography_algebra_natives_enabled
fun abort_unless_cryptography_algebra_natives_enabled()
Implementation
fun abort_unless_cryptography_algebra_natives_enabled() { if (features::cryptography_algebra_enabled()) return; abort(std::error::not_implemented(0))}
handles_from_elements
fun handles_from_elements<S>(elements: &vector<crypto_algebra::Element<S>>): vector<u64>
Implementation
fun handles_from_elements<S>(elements: &vector<Element<S>>): vector<u64> { let num_elements = elements.length(); let element_handles = std::vector::empty(); let i = 0; while ({ spec { invariant len(element_handles) == i; invariant forall k in 0..i: element_handles[k] == elements[k].handle; }; i < num_elements }) { element_handles.push_back(elements[i].handle); i += 1; }; element_handles}
add_internal
fun add_internal<S>(handle_1: u64, handle_2: u64): u64
Implementation
native fun add_internal<S>(handle_1: u64, handle_2: u64): u64;
deserialize_internal
fun deserialize_internal<S, F>(bytes: &vector<u8>): (bool, u64)
Implementation
native fun deserialize_internal<S, F>(bytes: &vector<u8>): (bool, u64);
div_internal
fun div_internal<F>(handle_1: u64, handle_2: u64): (bool, u64)
Implementation
native fun div_internal<F>(handle_1: u64, handle_2: u64): (bool, u64);
double_internal
fun double_internal<G>(element_handle: u64): u64
Implementation
native fun double_internal<G>(element_handle: u64): u64;
downcast_internal
fun downcast_internal<L, S>(handle: u64): (bool, u64)
Implementation
native fun downcast_internal<L,S>(handle: u64): (bool, u64);
from_u64_internal
fun from_u64_internal<S>(value: u64): u64
Implementation
native fun from_u64_internal<S>(value: u64): u64;
eq_internal
fun eq_internal<S>(handle_1: u64, handle_2: u64): bool
Implementation
native fun eq_internal<S>(handle_1: u64, handle_2: u64): bool;
hash_to_internal
fun hash_to_internal<S, H>(dst: &vector<u8>, bytes: &vector<u8>): u64
Implementation
native fun hash_to_internal<S, H>(dst: &vector<u8>, bytes: &vector<u8>): u64;
inv_internal
fun inv_internal<F>(handle: u64): (bool, u64)
Implementation
native fun inv_internal<F>(handle: u64): (bool, u64);
mul_internal
fun mul_internal<F>(handle_1: u64, handle_2: u64): u64
Implementation
native fun mul_internal<F>(handle_1: u64, handle_2: u64): u64;
multi_pairing_internal
fun multi_pairing_internal<G1, G2, Gt>(g1_handles: vector<u64>, g2_handles: vector<u64>): u64
Implementation
native fun multi_pairing_internal<G1,G2,Gt>(g1_handles: vector<u64>, g2_handles: vector<u64>): u64;
multi_scalar_mul_internal
fun multi_scalar_mul_internal<G, S>(element_handles: vector<u64>, scalar_handles: vector<u64>): u64
Implementation
native fun multi_scalar_mul_internal<G, S>(element_handles: vector<u64>, scalar_handles: vector<u64>): u64;
neg_internal
fun neg_internal<F>(handle: u64): u64
Implementation
native fun neg_internal<F>(handle: u64): u64;
one_internal
fun one_internal<S>(): u64
Implementation
native fun one_internal<S>(): u64;
order_internal
fun order_internal<G>(): vector<u8>
Implementation
native fun order_internal<G>(): vector<u8>;
pairing_internal
fun pairing_internal<G1, G2, Gt>(g1_handle: u64, g2_handle: u64): u64
Implementation
native fun pairing_internal<G1,G2,Gt>(g1_handle: u64, g2_handle: u64): u64;
scalar_mul_internal
fun scalar_mul_internal<G, S>(element_handle: u64, scalar_handle: u64): u64
Implementation
native fun scalar_mul_internal<G, S>(element_handle: u64, scalar_handle: u64): u64;
serialize_internal
fun serialize_internal<S, F>(handle: u64): vector<u8>
Implementation
native fun serialize_internal<S, F>(handle: u64): vector<u8>;
sqr_internal
fun sqr_internal<G>(handle: u64): u64
Implementation
native fun sqr_internal<G>(handle: u64): u64;
sub_internal
fun sub_internal<G>(handle_1: u64, handle_2: u64): u64
Implementation
native fun sub_internal<G>(handle_1: u64, handle_2: u64): u64;
upcast_internal
fun upcast_internal<S, L>(handle: u64): u64
Implementation
native fun upcast_internal<S,L>(handle: u64): u64;
zero_internal
fun zero_internal<S>(): u64
Implementation
native fun zero_internal<S>(): u64;
Specification
handles_from_elements
fun handles_from_elements<S>(elements: &vector<crypto_algebra::Element<S>>): vector<u64>
aborts_if false;ensures forall i in 0..len(elements): result[i] == elements[i].handle;
add_internal
fun add_internal<S>(handle_1: u64, handle_2: u64): u64
pragma opaque;
deserialize_internal
fun deserialize_internal<S, F>(bytes: &vector<u8>): (bool, u64)
pragma opaque;
div_internal
fun div_internal<F>(handle_1: u64, handle_2: u64): (bool, u64)
pragma opaque;
double_internal
fun double_internal<G>(element_handle: u64): u64
pragma opaque;
downcast_internal
fun downcast_internal<L, S>(handle: u64): (bool, u64)
pragma opaque;
from_u64_internal
fun from_u64_internal<S>(value: u64): u64
pragma opaque;
eq_internal
fun eq_internal<S>(handle_1: u64, handle_2: u64): bool
pragma opaque;
hash_to_internal
fun hash_to_internal<S, H>(dst: &vector<u8>, bytes: &vector<u8>): u64
pragma opaque;
inv_internal
fun inv_internal<F>(handle: u64): (bool, u64)
pragma opaque;
mul_internal
fun mul_internal<F>(handle_1: u64, handle_2: u64): u64
pragma opaque;
multi_pairing_internal
fun multi_pairing_internal<G1, G2, Gt>(g1_handles: vector<u64>, g2_handles: vector<u64>): u64
pragma opaque;
multi_scalar_mul_internal
fun multi_scalar_mul_internal<G, S>(element_handles: vector<u64>, scalar_handles: vector<u64>): u64
pragma opaque;
neg_internal
fun neg_internal<F>(handle: u64): u64
pragma opaque;
one_internal
fun one_internal<S>(): u64
pragma opaque;
order_internal
fun order_internal<G>(): vector<u8>
pragma opaque;
pairing_internal
fun pairing_internal<G1, G2, Gt>(g1_handle: u64, g2_handle: u64): u64
pragma opaque;
scalar_mul_internal
fun scalar_mul_internal<G, S>(element_handle: u64, scalar_handle: u64): u64
pragma opaque;
serialize_internal
fun serialize_internal<S, F>(handle: u64): vector<u8>
pragma opaque;
sqr_internal
fun sqr_internal<G>(handle: u64): u64
pragma opaque;
sub_internal
fun sub_internal<G>(handle_1: u64, handle_2: u64): u64
pragma opaque;
upcast_internal
fun upcast_internal<S, L>(handle: u64): u64
pragma opaque;
zero_internal
fun zero_internal<S>(): u64
pragma opaque;