Skip to content

ristretto255 - [mainnet]

This module contains functions for Ristretto255 curve arithmetic, assuming addition as the group operation.

The order of the Ristretto255 elliptic curve group is =2252+27742317777372353535851937790883648493\ell = 2^252 + 27742317777372353535851937790883648493, same as the order of the prime-order subgroup of Curve25519.

This module provides two structs for encoding Ristretto elliptic curves to the developer:

  • First, a 32-byte-sized CompressedRistretto struct, which is used to persist points in storage.

  • Second, a larger, in-memory, RistrettoPoint struct, which is decompressable from a CompressedRistretto struct. This larger struct can be used for fast arithmetic operations (additions, multiplications, etc.). The results can be saved back into storage by compressing RistrettoPoint structs back to CompressedRistretto structs.

This module also provides a Scalar struct for persisting scalars in storage and doing fast arithmetic on them.

One invariant maintained by this module is that all CompressedRistretto structs store a canonically-encoded point, which can always be decompressed into a valid point on the curve as a RistrettoPoint struct. Unfortunately, due to limitations in our underlying curve25519-dalek elliptic curve library, this decompression will unnecessarily verify the validity of the point and thus slightly decrease performance.

Similarly, all Scalar structs store a canonically-encoded scalar, which can always be safely operated on using arithmetic operations.

In the future, we might support additional features:

  • For scalars:
  • batch_invert()
  • For points:
  • double()
  • The challenge is that curve25519-dalek does NOT export double for Ristretto points (nor for Edwards)
  • double_and_compress_batch()

  • fixed-base, variable-time via optional_mixed_multiscalar_mul() in VartimePrecomputedMultiscalarMul

  • This would require a storage-friendly RistrettoBasepointTable and an in-memory variant of it too
  • Similar to the CompressedRistretto and RistrettoPoint structs in this module
  • The challenge is that curve25519-dalek’s RistrettoBasepointTable is not serializable
use 0x1::error;
use 0x1::features;
use 0x1::option;
use 0x1::vector;

Constants

The native function has not been deployed yet.

const E_NATIVE_FUN_NOT_AVAILABLE: u64 = 5;

The basepoint (generator) of the Ristretto255 group

const BASE_POINT: vector<u8> = [226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227, 11, 106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118];

The number of scalars does not match the number of points.

const E_DIFFERENT_NUM_POINTS_AND_SCALARS: u64 = 1;

Too many points have been created in the current transaction execution.

const E_TOO_MANY_POINTS_CREATED: u64 = 4;

Expected more than zero points as input.

const E_ZERO_POINTS: u64 = 2;

Expected more than zero scalars as input.

const E_ZERO_SCALARS: u64 = 3;

The hash of the basepoint of the Ristretto255 group using SHA3_512

const HASH_BASE_POINT: vector<u8> = [140, 146, 64, 180, 86, 169, 230, 220, 101, 195, 119, 161, 4, 141, 116, 95, 148, 160, 140, 219, 127, 68, 203, 205, 123, 70, 243, 64, 72, 135, 17, 52];

ORDER_ELL - 1: i.e., the “largest”, reduced scalar in the field

const L_MINUS_ONE: vector<u8> = [236, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16];

The maximum size in bytes of a canonically-encoded Ristretto255 point is 32 bytes.

const MAX_POINT_NUM_BYTES: u64 = 32;

The maximum size in bits of a canonically-encoded Scalar is 256 bits.

const MAX_SCALAR_NUM_BITS: u64 = 256;

The maximum size in bytes of a canonically-encoded Scalar is 32 bytes.

const MAX_SCALAR_NUM_BYTES: u64 = 32;

The order of the Ristretto255 group and its scalar field, in little-endian.

const ORDER_ELL: vector<u8> = [237, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16];

Structs

Scalar

This struct represents a scalar as a little-endian byte encoding of an integer in Z\mathbb{Z}_\ell, which is stored in data. Here, \ell denotes the order of the scalar field (and the underlying elliptic curve group).

struct Scalar has copy, drop, store
Fields
data: vector<u8>

CompressedRistretto

This struct represents a serialized point on the Ristretto255 curve, in 32 bytes. This struct can be decompressed from storage into an in-memory RistrettoPoint, on which fast curve arithmetic can be performed.

struct CompressedRistretto has copy, drop, store
Fields
data: vector<u8>

RistrettoPoint

This struct represents an in-memory Ristretto255 point and supports fast curve arithmetic.

An important invariant: There will never be two RistrettoPoint’s constructed with the same handle. One can have immutable references to the same RistrettoPoint, of course.

struct RistrettoPoint has drop
Fields
handle: u64

Functions

point_identity_compressed

Returns the identity point as a CompressedRistretto.

public fun point_identity_compressed(): ristretto255::CompressedRistretto
Implementation
public fun point_identity_compressed(): CompressedRistretto {
CompressedRistretto {
data: x"0000000000000000000000000000000000000000000000000000000000000000"
}
}

point_identity

Returns the identity point as a CompressedRistretto.

public fun point_identity(): ristretto255::RistrettoPoint
Implementation
public fun point_identity(): RistrettoPoint {
RistrettoPoint {
handle: point_identity_internal()
}
}

basepoint_compressed

Returns the basepoint (generator) of the Ristretto255 group as a compressed point

public fun basepoint_compressed(): ristretto255::CompressedRistretto
Implementation
public fun basepoint_compressed(): CompressedRistretto {
CompressedRistretto {
data: BASE_POINT
}
}

hash_to_point_base

Returns the hash-to-point result of serializing the basepoint of the Ristretto255 group. For use as the random value basepoint in Pedersen commitments

public fun hash_to_point_base(): ristretto255::RistrettoPoint
Implementation
public fun hash_to_point_base(): RistrettoPoint {
let comp_res = CompressedRistretto { data: HASH_BASE_POINT };
point_decompress(&comp_res)
}

basepoint

Returns the basepoint (generator) of the Ristretto255 group

public fun basepoint(): ristretto255::RistrettoPoint
Implementation
public fun basepoint(): RistrettoPoint {
let (handle, _) = point_decompress_internal(BASE_POINT);
RistrettoPoint {
handle
}
}

basepoint_mul

Multiplies the basepoint (generator) of the Ristretto255 group by a scalar and returns the result. This call is much faster than point_mul(&basepoint(), &some_scalar) because of precomputation tables.

public fun basepoint_mul(a: &ristretto255::Scalar): ristretto255::RistrettoPoint
Implementation
public fun basepoint_mul(a: &Scalar): RistrettoPoint {
RistrettoPoint {
handle: basepoint_mul_internal(a.data)
}
}

new_compressed_point_from_bytes

Creates a new CompressedRistretto point from a sequence of 32 bytes. If those bytes do not represent a valid point, returns None.

public fun new_compressed_point_from_bytes(bytes: vector<u8>): option::Option<ristretto255::CompressedRistretto>
Implementation
public fun new_compressed_point_from_bytes(bytes: vector<u8>): Option<CompressedRistretto> {
if (point_is_canonical_internal(bytes)) {
std::option::some(CompressedRistretto {
data: bytes
})
} else {
std::option::none<CompressedRistretto>()
}
}

new_point_from_bytes

Creates a new RistrettoPoint from a sequence of 32 bytes. If those bytes do not represent a valid point, returns None.

public fun new_point_from_bytes(bytes: vector<u8>): option::Option<ristretto255::RistrettoPoint>
Implementation
public fun new_point_from_bytes(bytes: vector<u8>): Option<RistrettoPoint> {
let (handle, is_canonical) = point_decompress_internal(bytes);
if (is_canonical) {
std::option::some(RistrettoPoint { handle })
} else {
std::option::none<RistrettoPoint>()
}
}

compressed_point_to_bytes

Given a compressed ristretto point point, returns the byte representation of that point

public fun compressed_point_to_bytes(point: ristretto255::CompressedRistretto): vector<u8>
Implementation
public fun compressed_point_to_bytes(point: CompressedRistretto): vector<u8> {
point.data
}

new_point_from_sha512

DEPRECATED: Use the more clearly-named new_point_from_sha2_512

Hashes the input to a uniformly-at-random RistrettoPoint via SHA512.

public fun new_point_from_sha512(sha2_512_input: vector<u8>): ristretto255::RistrettoPoint
Implementation
public fun new_point_from_sha512(sha2_512_input: vector<u8>): RistrettoPoint {
new_point_from_sha2_512(sha2_512_input)
}

new_point_from_sha2_512

Hashes the input to a uniformly-at-random RistrettoPoint via SHA2-512.

public fun new_point_from_sha2_512(sha2_512_input: vector<u8>): ristretto255::RistrettoPoint
Implementation
public fun new_point_from_sha2_512(sha2_512_input: vector<u8>): RistrettoPoint {
RistrettoPoint {
handle: new_point_from_sha512_internal(sha2_512_input)
}
}

new_point_from_64_uniform_bytes

Samples a uniformly-at-random RistrettoPoint given a sequence of 64 uniformly-at-random bytes. This function can be used to build a collision-resistant hash function that maps 64-byte messages to RistrettoPoint’s.

public fun new_point_from_64_uniform_bytes(bytes: vector<u8>): option::Option<ristretto255::RistrettoPoint>
Implementation
public fun new_point_from_64_uniform_bytes(bytes: vector<u8>): Option<RistrettoPoint> {
if (bytes.length() == 64) {
std::option::some(RistrettoPoint {
handle: new_point_from_64_uniform_bytes_internal(bytes)
})
} else {
std::option::none<RistrettoPoint>()
}
}

point_decompress

Decompresses a CompressedRistretto from storage into a RistrettoPoint which can be used for fast arithmetic.

public fun point_decompress(point: &ristretto255::CompressedRistretto): ristretto255::RistrettoPoint
Implementation
public fun point_decompress(point: &CompressedRistretto): RistrettoPoint {
// NOTE: Our CompressedRistretto invariant assures us that every CompressedRistretto in storage is a valid
// RistrettoPoint
let (handle, _) = point_decompress_internal(point.data);
RistrettoPoint { handle }
}

point_clone

Clones a RistrettoPoint.

public fun point_clone(point: &ristretto255::RistrettoPoint): ristretto255::RistrettoPoint
Implementation
public fun point_clone(point: &RistrettoPoint): RistrettoPoint {
if(!features::bulletproofs_enabled()) {
abort(std::error::invalid_state(E_NATIVE_FUN_NOT_AVAILABLE))
};
RistrettoPoint {
handle: point_clone_internal(point.handle)
}
}

point_compress

Compresses a RistrettoPoint to a CompressedRistretto which can be put in storage.

public fun point_compress(point: &ristretto255::RistrettoPoint): ristretto255::CompressedRistretto
Implementation
public fun point_compress(point: &RistrettoPoint): CompressedRistretto {
CompressedRistretto {
data: point_compress_internal(point)
}
}

point_to_bytes

Returns the sequence of bytes representin this Ristretto point. To convert a RistrettoPoint ‘p’ to bytes, first compress it via c = point_compress(&p), and then call this function on c.

public fun point_to_bytes(point: &ristretto255::CompressedRistretto): vector<u8>
Implementation
public fun point_to_bytes(point: &CompressedRistretto): vector<u8> {
point.data
}

point_mul

Returns a * point.

public fun point_mul(point: &ristretto255::RistrettoPoint, a: &ristretto255::Scalar): ristretto255::RistrettoPoint
Implementation
public fun point_mul(point: &RistrettoPoint, a: &Scalar): RistrettoPoint {
RistrettoPoint {
handle: point_mul_internal(point, a.data, false)
}
}

point_mul_assign

Sets a *= point and returns ‘a’.

public fun point_mul_assign(point: &mut ristretto255::RistrettoPoint, a: &ristretto255::Scalar): &mut ristretto255::RistrettoPoint
Implementation
public fun point_mul_assign(point: &mut RistrettoPoint, a: &Scalar): &mut RistrettoPoint {
point_mul_internal(point, a.data, true);
point
}

basepoint_double_mul

Returns (a * a_base + b * base_point), where base_point is the Ristretto basepoint encoded in BASE_POINT.

public fun basepoint_double_mul(a: &ristretto255::Scalar, a_base: &ristretto255::RistrettoPoint, b: &ristretto255::Scalar): ristretto255::RistrettoPoint
Implementation
public fun basepoint_double_mul(a: &Scalar, a_base: &RistrettoPoint, b: &Scalar): RistrettoPoint {
RistrettoPoint {
handle: basepoint_double_mul_internal(a.data, a_base, b.data)
}
}

point_add

Returns a + b

public fun point_add(a: &ristretto255::RistrettoPoint, b: &ristretto255::RistrettoPoint): ristretto255::RistrettoPoint
Implementation
public fun point_add(a: &RistrettoPoint, b: &RistrettoPoint): RistrettoPoint {
RistrettoPoint {
handle: point_add_internal(a, b, false)
}
}

point_add_assign

Sets a += b and returns ‘a’.

public fun point_add_assign(a: &mut ristretto255::RistrettoPoint, b: &ristretto255::RistrettoPoint): &mut ristretto255::RistrettoPoint
Implementation
public fun point_add_assign(a: &mut RistrettoPoint, b: &RistrettoPoint): &mut RistrettoPoint {
point_add_internal(a, b, true);
a
}

point_sub

Returns a - b

public fun point_sub(a: &ristretto255::RistrettoPoint, b: &ristretto255::RistrettoPoint): ristretto255::RistrettoPoint
Implementation
public fun point_sub(a: &RistrettoPoint, b: &RistrettoPoint): RistrettoPoint {
RistrettoPoint {
handle: point_sub_internal(a, b, false)
}
}

point_sub_assign

Sets a -= b and returns ‘a’.

public fun point_sub_assign(a: &mut ristretto255::RistrettoPoint, b: &ristretto255::RistrettoPoint): &mut ristretto255::RistrettoPoint
Implementation
public fun point_sub_assign(a: &mut RistrettoPoint, b: &RistrettoPoint): &mut RistrettoPoint {
point_sub_internal(a, b, true);
a
}

point_neg

Returns -a

public fun point_neg(a: &ristretto255::RistrettoPoint): ristretto255::RistrettoPoint
Implementation
public fun point_neg(a: &RistrettoPoint): RistrettoPoint {
RistrettoPoint {
handle: point_neg_internal(a, false)
}
}

point_neg_assign

Sets a = -a, and returns ‘a’.

public fun point_neg_assign(a: &mut ristretto255::RistrettoPoint): &mut ristretto255::RistrettoPoint
Implementation
public fun point_neg_assign(a: &mut RistrettoPoint): &mut RistrettoPoint {
point_neg_internal(a, true);
a
}

point_equals

Returns true if the two RistrettoPoints are the same points on the elliptic curve.

public fun point_equals(g: &ristretto255::RistrettoPoint, h: &ristretto255::RistrettoPoint): bool
Implementation
native public fun point_equals(g: &RistrettoPoint, h: &RistrettoPoint): bool;

double_scalar_mul

Computes a double-scalar multiplication, returning a_1 p_1 + a_2 p_2 This function is much faster than computing each a_i p_i using point_mul and adding up the results using point_add.

public fun double_scalar_mul(scalar1: &ristretto255::Scalar, point1: &ristretto255::RistrettoPoint, scalar2: &ristretto255::Scalar, point2: &ristretto255::RistrettoPoint): ristretto255::RistrettoPoint
Implementation
public fun double_scalar_mul(scalar1: &Scalar, point1: &RistrettoPoint, scalar2: &Scalar, point2: &RistrettoPoint): RistrettoPoint {
if(!features::bulletproofs_enabled()) {
abort(std::error::invalid_state(E_NATIVE_FUN_NOT_AVAILABLE))
};
RistrettoPoint {
handle: double_scalar_mul_internal(point1.handle, point2.handle, scalar1.data, scalar2.data)
}
}

multi_scalar_mul

Computes a multi-scalar multiplication, returning a_1 p_1 + a_2 p_2 + … + a_n p_n. This function is much faster than computing each a_i p_i using point_mul and adding up the results using point_add.

public fun multi_scalar_mul(points: &vector<ristretto255::RistrettoPoint>, scalars: &vector<ristretto255::Scalar>): ristretto255::RistrettoPoint
Implementation
public fun multi_scalar_mul(points: &vector<RistrettoPoint>, scalars: &vector<Scalar>): RistrettoPoint {
assert!(!points.is_empty(), std::error::invalid_argument(E_ZERO_POINTS));
assert!(!scalars.is_empty(), std::error::invalid_argument(E_ZERO_SCALARS));
assert!(
points.length() == scalars.length(), std::error::invalid_argument(E_DIFFERENT_NUM_POINTS_AND_SCALARS));
RistrettoPoint {
handle: multi_scalar_mul_internal<RistrettoPoint, Scalar>(points, scalars)
}
}

new_scalar_from_bytes

Given a sequence of 32 bytes, checks if they canonically-encode a Scalar and return it. Otherwise, returns None.

public fun new_scalar_from_bytes(bytes: vector<u8>): option::Option<ristretto255::Scalar>
Implementation
public fun new_scalar_from_bytes(bytes: vector<u8>): Option<Scalar> {
if (scalar_is_canonical_internal(bytes)) {
std::option::some(Scalar {
data: bytes
})
} else {
std::option::none<Scalar>()
}
}

new_scalar_from_sha512

DEPRECATED: Use the more clearly-named new_scalar_from_sha2_512

Hashes the input to a uniformly-at-random Scalar via SHA2-512

public fun new_scalar_from_sha512(sha2_512_input: vector<u8>): ristretto255::Scalar
Implementation
public fun new_scalar_from_sha512(sha2_512_input: vector<u8>): Scalar {
new_scalar_from_sha2_512(sha2_512_input)
}

new_scalar_from_sha2_512

Hashes the input to a uniformly-at-random Scalar via SHA2-512

public fun new_scalar_from_sha2_512(sha2_512_input: vector<u8>): ristretto255::Scalar
Implementation
public fun new_scalar_from_sha2_512(sha2_512_input: vector<u8>): Scalar {
Scalar {
data: scalar_from_sha512_internal(sha2_512_input)
}
}

new_scalar_from_u8

Creates a Scalar from an u8.

public fun new_scalar_from_u8(byte: u8): ristretto255::Scalar
Implementation
public fun new_scalar_from_u8(byte: u8): Scalar {
let s = scalar_zero();
s.data[0] = byte;
s
}

new_scalar_from_u32

Creates a Scalar from an u32.

public fun new_scalar_from_u32(four_bytes: u32): ristretto255::Scalar
Implementation
public fun new_scalar_from_u32(four_bytes: u32): Scalar {
Scalar {
data: scalar_from_u64_internal((four_bytes as u64))
}
}

new_scalar_from_u64

Creates a Scalar from an u64.

public fun new_scalar_from_u64(eight_bytes: u64): ristretto255::Scalar
Implementation
public fun new_scalar_from_u64(eight_bytes: u64): Scalar {
Scalar {
data: scalar_from_u64_internal(eight_bytes)
}
}

new_scalar_from_u128

Creates a Scalar from an u128.

public fun new_scalar_from_u128(sixteen_bytes: u128): ristretto255::Scalar
Implementation
public fun new_scalar_from_u128(sixteen_bytes: u128): Scalar {
Scalar {
data: scalar_from_u128_internal(sixteen_bytes)
}
}

new_scalar_reduced_from_32_bytes

Creates a Scalar from 32 bytes by reducing the little-endian-encoded number in those bytes modulo \ell.

public fun new_scalar_reduced_from_32_bytes(bytes: vector<u8>): option::Option<ristretto255::Scalar>
Implementation
public fun new_scalar_reduced_from_32_bytes(bytes: vector<u8>): Option<Scalar> {
if (bytes.length() == 32) {
std::option::some(Scalar {
data: scalar_reduced_from_32_bytes_internal(bytes)
})
} else {
std::option::none()
}
}

new_scalar_uniform_from_64_bytes

Samples a scalar uniformly-at-random given 64 uniform-at-random bytes as input by reducing the little-endian-encoded number in those bytes modulo \ell.

public fun new_scalar_uniform_from_64_bytes(bytes: vector<u8>): option::Option<ristretto255::Scalar>
Implementation
public fun new_scalar_uniform_from_64_bytes(bytes: vector<u8>): Option<Scalar> {
if (bytes.length() == 64) {
std::option::some(Scalar {
data: scalar_uniform_from_64_bytes_internal(bytes)
})
} else {
std::option::none()
}
}

scalar_zero

Returns 0 as a Scalar.

public fun scalar_zero(): ristretto255::Scalar
Implementation
public fun scalar_zero(): Scalar {
Scalar {
data: x"0000000000000000000000000000000000000000000000000000000000000000"
}
}

scalar_is_zero

Returns true if the given Scalar equals 0.

public fun scalar_is_zero(s: &ristretto255::Scalar): bool
Implementation
public fun scalar_is_zero(s: &Scalar): bool {
s.data == x"0000000000000000000000000000000000000000000000000000000000000000"
}

scalar_one

Returns 1 as a Scalar.

public fun scalar_one(): ristretto255::Scalar
Implementation
public fun scalar_one(): Scalar {
Scalar {
data: x"0100000000000000000000000000000000000000000000000000000000000000"
}
}

scalar_is_one

Returns true if the given Scalar equals 1.

public fun scalar_is_one(s: &ristretto255::Scalar): bool
Implementation
public fun scalar_is_one(s: &Scalar): bool {
s.data == x"0100000000000000000000000000000000000000000000000000000000000000"
}

scalar_equals

Returns true if the two scalars are equal.

public fun scalar_equals(lhs: &ristretto255::Scalar, rhs: &ristretto255::Scalar): bool
Implementation
public fun scalar_equals(lhs: &Scalar, rhs: &Scalar): bool {
lhs.data == rhs.data
}

scalar_invert

Returns the inverse s^{-1} mod \ell of a scalar s. Returns None if s is zero.

public fun scalar_invert(s: &ristretto255::Scalar): option::Option<ristretto255::Scalar>
Implementation
public fun scalar_invert(s: &Scalar): Option<Scalar> {
if (scalar_is_zero(s)) {
std::option::none<Scalar>()
} else {
std::option::some(Scalar {
data: scalar_invert_internal(s.data)
})
}
}

scalar_mul

Returns the product of the two scalars.

public fun scalar_mul(a: &ristretto255::Scalar, b: &ristretto255::Scalar): ristretto255::Scalar
Implementation
public fun scalar_mul(a: &Scalar, b: &Scalar): Scalar {
Scalar {
data: scalar_mul_internal(a.data, b.data)
}
}

scalar_mul_assign

Computes the product of ‘a’ and ‘b’ and assigns the result to ‘a’. Returns ‘a’.

public fun scalar_mul_assign(a: &mut ristretto255::Scalar, b: &ristretto255::Scalar): &mut ristretto255::Scalar
Implementation
public fun scalar_mul_assign(a: &mut Scalar, b: &Scalar): &mut Scalar {
a.data = scalar_mul(a, b).data;
a
}

scalar_add

Returns the sum of the two scalars.

public fun scalar_add(a: &ristretto255::Scalar, b: &ristretto255::Scalar): ristretto255::Scalar
Implementation
public fun scalar_add(a: &Scalar, b: &Scalar): Scalar {
Scalar {
data: scalar_add_internal(a.data, b.data)
}
}

scalar_add_assign

Computes the sum of ‘a’ and ‘b’ and assigns the result to ‘a’ Returns ‘a’.

public fun scalar_add_assign(a: &mut ristretto255::Scalar, b: &ristretto255::Scalar): &mut ristretto255::Scalar
Implementation
public fun scalar_add_assign(a: &mut Scalar, b: &Scalar): &mut Scalar {
a.data = scalar_add(a, b).data;
a
}

scalar_sub

Returns the difference of the two scalars.

public fun scalar_sub(a: &ristretto255::Scalar, b: &ristretto255::Scalar): ristretto255::Scalar
Implementation
public fun scalar_sub(a: &Scalar, b: &Scalar): Scalar {
Scalar {
data: scalar_sub_internal(a.data, b.data)
}
}

scalar_sub_assign

Subtracts ‘b’ from ‘a’ and assigns the result to ‘a’. Returns ‘a’.

public fun scalar_sub_assign(a: &mut ristretto255::Scalar, b: &ristretto255::Scalar): &mut ristretto255::Scalar
Implementation
public fun scalar_sub_assign(a: &mut Scalar, b: &Scalar): &mut Scalar {
a.data = scalar_sub(a, b).data;
a
}

scalar_neg

Returns the negation of ‘a’: i.e., (0a)mod(0 - a) \mod \ell.

public fun scalar_neg(a: &ristretto255::Scalar): ristretto255::Scalar
Implementation
public fun scalar_neg(a: &Scalar): Scalar {
Scalar {
data: scalar_neg_internal(a.data)
}
}

scalar_neg_assign

Replaces ‘a’ by its negation. Returns ‘a’.

public fun scalar_neg_assign(a: &mut ristretto255::Scalar): &mut ristretto255::Scalar
Implementation
public fun scalar_neg_assign(a: &mut Scalar): &mut Scalar {
a.data = scalar_neg(a).data;
a
}

scalar_to_bytes

Returns the byte-representation of the scalar.

public fun scalar_to_bytes(s: &ristretto255::Scalar): vector<u8>
Implementation
public fun scalar_to_bytes(s: &Scalar): vector<u8> {
s.data
}

new_point_from_sha512_internal

fun new_point_from_sha512_internal(sha2_512_input: vector<u8>): u64
Implementation
native fun new_point_from_sha512_internal(sha2_512_input: vector<u8>): u64;

new_point_from_64_uniform_bytes_internal

fun new_point_from_64_uniform_bytes_internal(bytes: vector<u8>): u64
Implementation
native fun new_point_from_64_uniform_bytes_internal(bytes: vector<u8>): u64;

point_is_canonical_internal

fun point_is_canonical_internal(bytes: vector<u8>): bool
Implementation
native fun point_is_canonical_internal(bytes: vector<u8>): bool;

point_identity_internal

fun point_identity_internal(): u64
Implementation
native fun point_identity_internal(): u64;

point_decompress_internal

fun point_decompress_internal(maybe_non_canonical_bytes: vector<u8>): (u64, bool)
Implementation
native fun point_decompress_internal(maybe_non_canonical_bytes: vector<u8>): (u64, bool);

point_clone_internal

fun point_clone_internal(point_handle: u64): u64
Implementation
native fun point_clone_internal(point_handle: u64): u64;

point_compress_internal

fun point_compress_internal(point: &ristretto255::RistrettoPoint): vector<u8>
Implementation
native fun point_compress_internal(point: &RistrettoPoint): vector<u8>;

point_mul_internal

fun point_mul_internal(point: &ristretto255::RistrettoPoint, a: vector<u8>, in_place: bool): u64
Implementation
native fun point_mul_internal(point: &RistrettoPoint, a: vector<u8>, in_place: bool): u64;

basepoint_mul_internal

fun basepoint_mul_internal(a: vector<u8>): u64
Implementation
native fun basepoint_mul_internal(a: vector<u8>): u64;

basepoint_double_mul_internal

fun basepoint_double_mul_internal(a: vector<u8>, some_point: &ristretto255::RistrettoPoint, b: vector<u8>): u64
Implementation
native fun basepoint_double_mul_internal(a: vector<u8>, some_point: &RistrettoPoint, b: vector<u8>): u64;

point_add_internal

fun point_add_internal(a: &ristretto255::RistrettoPoint, b: &ristretto255::RistrettoPoint, in_place: bool): u64
Implementation
native fun point_add_internal(a: &RistrettoPoint, b: &RistrettoPoint, in_place: bool): u64;

point_sub_internal

fun point_sub_internal(a: &ristretto255::RistrettoPoint, b: &ristretto255::RistrettoPoint, in_place: bool): u64
Implementation
native fun point_sub_internal(a: &RistrettoPoint, b: &RistrettoPoint, in_place: bool): u64;

point_neg_internal

fun point_neg_internal(a: &ristretto255::RistrettoPoint, in_place: bool): u64
Implementation
native fun point_neg_internal(a: &RistrettoPoint, in_place: bool): u64;

double_scalar_mul_internal

fun double_scalar_mul_internal(point1: u64, point2: u64, scalar1: vector<u8>, scalar2: vector<u8>): u64
Implementation
native fun double_scalar_mul_internal(point1: u64, point2: u64, scalar1: vector<u8>, scalar2: vector<u8>): u64;

multi_scalar_mul_internal

The generic arguments are needed to deal with some Move VM peculiarities which prevent us from borrowing the points (or scalars) inside a &vector in Rust.

WARNING: This function can only be called with P = RistrettoPoint and S = Scalar.

fun multi_scalar_mul_internal<P, S>(points: &vector<P>, scalars: &vector<S>): u64
Implementation
native fun multi_scalar_mul_internal<P, S>(points: &vector<P>, scalars: &vector<S>): u64;

scalar_is_canonical_internal

fun scalar_is_canonical_internal(s: vector<u8>): bool
Implementation
native fun scalar_is_canonical_internal(s: vector<u8>): bool;

scalar_from_u64_internal

fun scalar_from_u64_internal(num: u64): vector<u8>
Implementation
native fun scalar_from_u64_internal(num: u64): vector<u8>;

scalar_from_u128_internal

fun scalar_from_u128_internal(num: u128): vector<u8>
Implementation
native fun scalar_from_u128_internal(num: u128): vector<u8>;

scalar_reduced_from_32_bytes_internal

fun scalar_reduced_from_32_bytes_internal(bytes: vector<u8>): vector<u8>
Implementation
native fun scalar_reduced_from_32_bytes_internal(bytes: vector<u8>): vector<u8>;

scalar_uniform_from_64_bytes_internal

fun scalar_uniform_from_64_bytes_internal(bytes: vector<u8>): vector<u8>
Implementation
native fun scalar_uniform_from_64_bytes_internal(bytes: vector<u8>): vector<u8>;

scalar_invert_internal

fun scalar_invert_internal(bytes: vector<u8>): vector<u8>
Implementation
native fun scalar_invert_internal(bytes: vector<u8>): vector<u8>;

scalar_from_sha512_internal

fun scalar_from_sha512_internal(sha2_512_input: vector<u8>): vector<u8>
Implementation
native fun scalar_from_sha512_internal(sha2_512_input: vector<u8>): vector<u8>;

scalar_mul_internal

fun scalar_mul_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>
Implementation
native fun scalar_mul_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>;

scalar_add_internal

fun scalar_add_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>
Implementation
native fun scalar_add_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>;

scalar_sub_internal

fun scalar_sub_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>
Implementation
native fun scalar_sub_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>;

scalar_neg_internal

fun scalar_neg_internal(a_bytes: vector<u8>): vector<u8>
Implementation
native fun scalar_neg_internal(a_bytes: vector<u8>): vector<u8>;

Specification

point_equals

public fun point_equals(g: &ristretto255::RistrettoPoint, h: &ristretto255::RistrettoPoint): bool
pragma opaque;

double_scalar_mul

public fun double_scalar_mul(scalar1: &ristretto255::Scalar, point1: &ristretto255::RistrettoPoint, scalar2: &ristretto255::Scalar, point2: &ristretto255::RistrettoPoint): ristretto255::RistrettoPoint
pragma opaque;

multi_scalar_mul

public fun multi_scalar_mul(points: &vector<ristretto255::RistrettoPoint>, scalars: &vector<ristretto255::Scalar>): ristretto255::RistrettoPoint
aborts_if len(points) == 0;
aborts_if len(scalars) == 0;
aborts_if len(points) != len(scalars);
ensures result.handle == spec_multi_scalar_mul_internal(points, scalars);

new_scalar_from_bytes

public fun new_scalar_from_bytes(bytes: vector<u8>): option::Option<ristretto255::Scalar>
aborts_if false;
ensures spec_scalar_is_canonical_internal(bytes) ==> (std::option::spec_is_some(result)
&& std::option::spec_borrow(result).data == bytes);
ensures !spec_scalar_is_canonical_internal(bytes) ==> std::option::spec_is_none(result);

new_scalar_from_sha2_512

public fun new_scalar_from_sha2_512(sha2_512_input: vector<u8>): ristretto255::Scalar
aborts_if false;
ensures result.data == spec_scalar_from_sha512_internal(sha2_512_input);

new_scalar_from_u8

public fun new_scalar_from_u8(byte: u8): ristretto255::Scalar
aborts_if false;
ensures result.data[0] == byte;
ensures forall i in 1..len(result.data): result.data[i] == 0;

new_scalar_from_u32

public fun new_scalar_from_u32(four_bytes: u32): ristretto255::Scalar
aborts_if false;
ensures result.data == spec_scalar_from_u64_internal(four_bytes);

new_scalar_from_u64

public fun new_scalar_from_u64(eight_bytes: u64): ristretto255::Scalar
aborts_if false;
ensures result.data == spec_scalar_from_u64_internal(eight_bytes);

new_scalar_from_u128

public fun new_scalar_from_u128(sixteen_bytes: u128): ristretto255::Scalar
aborts_if false;
ensures result.data == spec_scalar_from_u128_internal(sixteen_bytes);

new_scalar_reduced_from_32_bytes

public fun new_scalar_reduced_from_32_bytes(bytes: vector<u8>): option::Option<ristretto255::Scalar>
ensures len(bytes) != 32 ==> std::option::spec_is_none(result);
ensures len(bytes) == 32 ==> std::option::spec_borrow(result).data == spec_scalar_reduced_from_32_bytes_internal(bytes);

new_scalar_uniform_from_64_bytes

public fun new_scalar_uniform_from_64_bytes(bytes: vector<u8>): option::Option<ristretto255::Scalar>
ensures len(bytes) != 64 ==> std::option::spec_is_none(result);
ensures len(bytes) == 64 ==> std::option::spec_borrow(result).data == spec_scalar_uniform_from_64_bytes_internal(bytes);

scalar_zero

public fun scalar_zero(): ristretto255::Scalar
ensures spec_scalar_is_zero(result);

scalar_is_zero

public fun scalar_is_zero(s: &ristretto255::Scalar): bool
ensures result == spec_scalar_is_zero(s);

scalar_one

public fun scalar_one(): ristretto255::Scalar
ensures spec_scalar_is_one(result);

scalar_is_one

public fun scalar_is_one(s: &ristretto255::Scalar): bool
ensures result == spec_scalar_is_one(s);

scalar_equals

public fun scalar_equals(lhs: &ristretto255::Scalar, rhs: &ristretto255::Scalar): bool
aborts_if false;
ensures result == (lhs.data == rhs.data);

scalar_invert

public fun scalar_invert(s: &ristretto255::Scalar): option::Option<ristretto255::Scalar>
aborts_if false;
ensures spec_scalar_is_zero(s) ==> std::option::spec_is_none(result);
ensures !spec_scalar_is_zero(s) ==> (std::option::spec_is_some(result) && std::option::spec_borrow(result).data == spec_scalar_invert_internal(s.data));

scalar_mul

public fun scalar_mul(a: &ristretto255::Scalar, b: &ristretto255::Scalar): ristretto255::Scalar
aborts_if false;
ensures result.data == spec_scalar_mul_internal(a.data, b.data);

scalar_mul_assign

public fun scalar_mul_assign(a: &mut ristretto255::Scalar, b: &ristretto255::Scalar): &mut ristretto255::Scalar
aborts_if false;
ensures a.data == spec_scalar_mul_internal(old(a).data, b.data);

scalar_add

public fun scalar_add(a: &ristretto255::Scalar, b: &ristretto255::Scalar): ristretto255::Scalar
aborts_if false;
ensures result.data == spec_scalar_add_internal(a.data, b.data);

scalar_add_assign

public fun scalar_add_assign(a: &mut ristretto255::Scalar, b: &ristretto255::Scalar): &mut ristretto255::Scalar
aborts_if false;
ensures a.data == spec_scalar_add_internal(old(a).data, b.data);

scalar_sub

public fun scalar_sub(a: &ristretto255::Scalar, b: &ristretto255::Scalar): ristretto255::Scalar
aborts_if false;
ensures result.data == spec_scalar_sub_internal(a.data, b.data);

scalar_sub_assign

public fun scalar_sub_assign(a: &mut ristretto255::Scalar, b: &ristretto255::Scalar): &mut ristretto255::Scalar
aborts_if false;
ensures a.data == spec_scalar_sub_internal(old(a).data, b.data);

scalar_neg

public fun scalar_neg(a: &ristretto255::Scalar): ristretto255::Scalar
pragma opaque;
aborts_if false;
ensures result.data == spec_scalar_neg_internal(a.data);

scalar_neg_assign

public fun scalar_neg_assign(a: &mut ristretto255::Scalar): &mut ristretto255::Scalar
aborts_if false;
ensures a.data == spec_scalar_neg_internal(old(a).data);

scalar_to_bytes

public fun scalar_to_bytes(s: &ristretto255::Scalar): vector<u8>
aborts_if false;
ensures result == s.data;

Helper functions

fun spec_scalar_is_zero(s: Scalar): bool {
s.data == x"0000000000000000000000000000000000000000000000000000000000000000"
}
fun spec_scalar_is_one(s: Scalar): bool {
s.data == x"0100000000000000000000000000000000000000000000000000000000000000"
}
fun spec_point_is_canonical_internal(bytes: vector<u8>): bool;
fun spec_double_scalar_mul_internal(point1: u64, point2: u64, scalar1: vector<u8>, scalar2: vector<u8>): u64;
fun spec_multi_scalar_mul_internal<P, S>(points: vector<P>, scalars: vector<S>): u64;
fun spec_scalar_is_canonical_internal(s: vector<u8>): bool;
fun spec_scalar_from_u64_internal(num: u64): vector<u8>;
fun spec_scalar_from_u128_internal(num: u128): vector<u8>;
fun spec_scalar_reduced_from_32_bytes_internal(bytes: vector<u8>): vector<u8>;
fun spec_scalar_uniform_from_64_bytes_internal(bytes: vector<u8>): vector<u8>;
fun spec_scalar_invert_internal(bytes: vector<u8>): vector<u8>;
fun spec_scalar_from_sha512_internal(sha2_512_input: vector<u8>): vector<u8>;
fun spec_scalar_mul_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>;
fun spec_scalar_add_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>;
fun spec_scalar_sub_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>;
fun spec_scalar_neg_internal(a_bytes: vector<u8>): vector<u8>;

new_point_from_sha512_internal

fun new_point_from_sha512_internal(sha2_512_input: vector<u8>): u64
pragma opaque;

new_point_from_64_uniform_bytes_internal

fun new_point_from_64_uniform_bytes_internal(bytes: vector<u8>): u64
pragma opaque;

point_is_canonical_internal

fun point_is_canonical_internal(bytes: vector<u8>): bool
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_point_is_canonical_internal(bytes);

point_identity_internal

fun point_identity_internal(): u64
pragma opaque;

point_decompress_internal

fun point_decompress_internal(maybe_non_canonical_bytes: vector<u8>): (u64, bool)
pragma opaque;

point_clone_internal

fun point_clone_internal(point_handle: u64): u64
pragma opaque;

point_compress_internal

fun point_compress_internal(point: &ristretto255::RistrettoPoint): vector<u8>
pragma opaque;

point_mul_internal

fun point_mul_internal(point: &ristretto255::RistrettoPoint, a: vector<u8>, in_place: bool): u64
pragma opaque;

basepoint_mul_internal

fun basepoint_mul_internal(a: vector<u8>): u64
pragma opaque;

basepoint_double_mul_internal

fun basepoint_double_mul_internal(a: vector<u8>, some_point: &ristretto255::RistrettoPoint, b: vector<u8>): u64
pragma opaque;

point_add_internal

fun point_add_internal(a: &ristretto255::RistrettoPoint, b: &ristretto255::RistrettoPoint, in_place: bool): u64
pragma opaque;

point_sub_internal

fun point_sub_internal(a: &ristretto255::RistrettoPoint, b: &ristretto255::RistrettoPoint, in_place: bool): u64
pragma opaque;

point_neg_internal

fun point_neg_internal(a: &ristretto255::RistrettoPoint, in_place: bool): u64
pragma opaque;

double_scalar_mul_internal

fun double_scalar_mul_internal(point1: u64, point2: u64, scalar1: vector<u8>, scalar2: vector<u8>): u64
pragma opaque;

multi_scalar_mul_internal

fun multi_scalar_mul_internal<P, S>(points: &vector<P>, scalars: &vector<S>): u64
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_multi_scalar_mul_internal<P, S>(points, scalars);

scalar_is_canonical_internal

fun scalar_is_canonical_internal(s: vector<u8>): bool
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_is_canonical_internal(s);

scalar_from_u64_internal

fun scalar_from_u64_internal(num: u64): vector<u8>
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_from_u64_internal(num);

scalar_from_u128_internal

fun scalar_from_u128_internal(num: u128): vector<u8>
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_from_u128_internal(num);

scalar_reduced_from_32_bytes_internal

fun scalar_reduced_from_32_bytes_internal(bytes: vector<u8>): vector<u8>
pragma opaque;
ensures result == spec_scalar_reduced_from_32_bytes_internal(bytes);

scalar_uniform_from_64_bytes_internal

fun scalar_uniform_from_64_bytes_internal(bytes: vector<u8>): vector<u8>
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_uniform_from_64_bytes_internal(bytes);

scalar_invert_internal

fun scalar_invert_internal(bytes: vector<u8>): vector<u8>
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_invert_internal(bytes);

scalar_from_sha512_internal

fun scalar_from_sha512_internal(sha2_512_input: vector<u8>): vector<u8>
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_from_sha512_internal(sha2_512_input);

scalar_mul_internal

fun scalar_mul_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_mul_internal(a_bytes, b_bytes);

scalar_add_internal

fun scalar_add_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_add_internal(a_bytes, b_bytes);

scalar_sub_internal

fun scalar_sub_internal(a_bytes: vector<u8>, b_bytes: vector<u8>): vector<u8>
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_sub_internal(a_bytes, b_bytes);

scalar_neg_internal

fun scalar_neg_internal(a_bytes: vector<u8>): vector<u8>
pragma opaque;
aborts_if [abstract] false;
ensures result == spec_scalar_neg_internal(a_bytes);