Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
32 changes: 23 additions & 9 deletions simf/asserts_test.simf
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
use crate::lib::asserts::{
assert_eq_1, assert_eq_8, assert_eq_16, assert_eq_32, assert_eq_64,assert_eq_128, assert_eq_256,
assert_none_1, assert_none_8, assert_none_16, assert_none_32, assert_none_64, assert_none_128, assert_none_256
assert_eq_1,
assert_eq_8,
assert_eq_16,
assert_eq_32,
assert_eq_64,
assert_eq_128,
assert_eq_256,
assert_eq_bool,
assert_none_1,
assert_none_8,
assert_none_16,
assert_none_32,
assert_none_64,
assert_none_128,
assert_none_256
};
use crate::helper::if_test_this_function;

Expand Down Expand Up @@ -36,13 +49,14 @@ fn main() {
match if_test_this_function(4, fn_idx) { true => { assert_eq_64(unwrap(a_u64), unwrap(b_u64)); }, false => (), };
match if_test_this_function(5, fn_idx) { true => { assert_eq_128(unwrap(a_u128), unwrap(b_u128)); }, false => (), };
match if_test_this_function(6, fn_idx) { true => { assert_eq_256(unwrap(a_u256), unwrap(b_u256)); }, false => (), };
match if_test_this_function(7, fn_idx) { true => { assert_eq_bool(<u1>::into(unwrap(a_u1)), <u1>::into(unwrap(b_u1))); }, false => (), };

// Assert None
match if_test_this_function(7, fn_idx) { true => { assert_none_1(a_u1); }, false => (), };
match if_test_this_function(8, fn_idx) { true => { assert_none_8(a_u8); }, false => (), };
match if_test_this_function(9, fn_idx) { true => { assert_none_16(a_u16); }, false => (), };
match if_test_this_function(10, fn_idx) { true => { assert_none_32(a_u32); }, false => (), };
match if_test_this_function(11, fn_idx) { true => { assert_none_64(a_u64); }, false => (), };
match if_test_this_function(12, fn_idx) { true => { assert_none_128(a_u128); }, false => (), };
match if_test_this_function(13, fn_idx) { true => { assert_none_256(a_u256); }, false => (), };
match if_test_this_function(8, fn_idx) { true => { assert_none_1(a_u1); }, false => (), };
match if_test_this_function(9, fn_idx) { true => { assert_none_8(a_u8); }, false => (), };
match if_test_this_function(10, fn_idx) { true => { assert_none_16(a_u16); }, false => (), };
match if_test_this_function(11, fn_idx) { true => { assert_none_32(a_u32); }, false => (), };
match if_test_this_function(12, fn_idx) { true => { assert_none_64(a_u64); }, false => (), };
match if_test_this_function(13, fn_idx) { true => { assert_none_128(a_u128); }, false => (), };
match if_test_this_function(14, fn_idx) { true => { assert_none_256(a_u256); }, false => (), };
}
38 changes: 38 additions & 0 deletions simf/ct_compile_check.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use crate::lib::ct::relations::{
zero, add, sub, add_scaled, sub_scaled, is_balanced, assert_balanced,
is_scaled_eq, assert_scaled_eq, is_value_eq, assert_value_eq,
assert_ratio_eq, assert_sum_eq
};
use crate::lib::ct::commitment::{
asset_generator, value_commitment,
assert_asset_generator, assert_value_commitment, assert_opens_to
};
use crate::lib::secp256k1::operations::point_to_ge;

fn main() {
let p: Point = witness::P;
let q: Point = witness::Q;
let s: Scalar = witness::S;
let id: u256 = witness::ID;
let asset: Asset1 = witness::ASSET;
let amount: Amount1 = witness::AMOUNT;

let acc: Gej = sub_scaled(add_scaled(sub(add(zero(), p), q), 2, p), 3, q);
assert!(is_balanced(acc, s));
assert_balanced(acc, s);

assert!(is_scaled_eq(q, 2, p, s));
assert_scaled_eq(q, 2, p, s);
assert!(is_value_eq(p, q, s));
assert_value_eq(p, q, s);
assert_ratio_eq(3, p, 5, q, s);
assert_sum_eq(p, q, p, s);

let h: Gej = asset_generator(id, s);
let c: Gej = value_commitment(7, h, s);
assert!(jet::gej_is_on_curve(c));

assert_asset_generator(point_to_ge(p), id, s);
assert_value_commitment(point_to_ge(p), 7, point_to_ge(q), s);
assert_opens_to(asset, amount, id, 7, s, s);
}
5 changes: 5 additions & 0 deletions simf/lib/asserts.simf
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ pub fn assert_eq_256(a: u256, b: u256) {
assert!(jet::eq_256(a, b));
}

/// Asserts that two bool values are equal
pub fn assert_eq_bool(a: bool, b: bool) {
assert_eq_1(<bool>::into(a), <bool>::into(b));
}

/// Asserts that provided `Option<u1>` value is a `None`
pub fn assert_none_1(val: Option<u1>) {
assert!(is_none::<u1>(val));
Expand Down
73 changes: 73 additions & 0 deletions simf/lib/ct/commitment.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Confidential Transactions: commitment builders and openings.
*
* H_a = hash_to_curve(asset_id) + abf*G (asset generator)
* C = v*H_a + vbf*G (value commitment)
*
* Every assert in this module takes blinding factors, which means the value or
* asset id it checks becomes PUBLIC to anyone reading the witness.
* For checks that constrain commitments while keeping the values sealed, use
* `crate::lib::ct::relations`.
*/

use crate::lib::asserts::{assert_eq_64, assert_eq_256};
use crate::lib::secp256k1::operations::point_to_ge;
use crate::lib::u64::u64_into_u256;

/// Builds the asset generator `H_a = hash_to_curve(asset_id) + abf*G`.
pub fn asset_generator(asset_id: u256, abf: Scalar) -> Gej {
jet::gej_ge_add(jet::generate(abf), jet::hash_to_curve(asset_id))
}

/// Builds the value commitment `C = v*asset_gen + vbf*G`.
pub fn value_commitment(v: u64, asset_gen: Gej, vbf: Scalar) -> Gej {
jet::linear_combination_1((u64_into_u256(v), asset_gen), vbf)
}

/// Asserts that `h == hash_to_curve(asset_id) + abf*G`.
pub fn assert_asset_generator(h: Ge, asset_id: u256, abf: Scalar) {
jet::linear_verify_1(((1, jet::hash_to_curve(asset_id)), abf), h);
}

/// Asserts that `c == v*h + vbf*G`, where `h` is the asset generator that `c`
/// commits against.
pub fn assert_value_commitment(c: Ge, v: u64, h: Ge, vbf: Scalar) {
jet::linear_verify_1(((u64_into_u256(v), h), vbf), c);
}

/// Asserts that an `(asset, amount)` pair opens to `expected_asset_id` and
/// `expected_amount`.
pub fn assert_opens_to(
asset: Asset1,
amount: Amount1,
expected_asset_id: u256,
expected_amount: u64,
abf: Scalar,
vbf: Scalar,
) {
match asset {
Left(conf_asset: Point) => {
let h: Ge = point_to_ge(conf_asset);
assert_asset_generator(h, expected_asset_id, abf);

match amount {
Left(conf_amount: Point) => {
assert_value_commitment(point_to_ge(conf_amount), expected_amount, h, vbf);
},
Right(explicit_amount: u64) => assert_eq_64(explicit_amount, expected_amount),
};
},
Right(explicit_asset: u256) => {
assert_eq_256(explicit_asset, expected_asset_id);

match amount {
// An explicit asset commits against the unblinded generator.
Left(conf_amount: Point) => {
let h: Ge = jet::hash_to_curve(expected_asset_id);
assert_value_commitment(point_to_ge(conf_amount), expected_amount, h, vbf);
},
Right(explicit_amount: u64) => assert_eq_64(explicit_amount, expected_amount),
};
},
};
}
79 changes: 79 additions & 0 deletions simf/lib/ct/relations.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Confidential Transactions: relations between commitments.
*
* Nothing here takes a blinding factor, so nothing here discloses a committed
* value. For checks that do reveal a value or an asset id, see
* `crate::lib::ct::commitment`.
*
* A value commitment expands to
*
* C = v*H_a + vbf*G = v*H_0 + (v*abf + vbf)*G
*
*/

use crate::lib::secp256k1::operations::{point_to_ge, point_to_gej};

/// The empty accumulator (the point at infinity).
pub fn zero() -> Gej {
jet::gej_infinity()
}

/// `acc + c`
pub fn add(acc: Gej, c: Point) -> Gej {
jet::gej_ge_add(acc, point_to_ge(c))
}

/// `acc - c`
pub fn sub(acc: Gej, c: Point) -> Gej {
jet::gej_ge_add(acc, jet::ge_negate(point_to_ge(c)))
}

/// `acc + k*c`
pub fn add_scaled(acc: Gej, k: Scalar, c: Point) -> Gej {
jet::gej_add(acc, jet::scale(k, point_to_gej(c)))
}

/// `acc - k*c`
pub fn sub_scaled(acc: Gej, k: Scalar, c: Point) -> Gej {
add_scaled(acc, jet::scalar_negate(k), c)
}

/// Returns true iff `acc == s*G`.
pub fn is_balanced(acc: Gej, s: Scalar) -> bool {
jet::gej_equiv(acc, jet::generate(s))
}

/// Asserts that `acc == s*G`.
pub fn assert_balanced(acc: Gej, s: Scalar) {
assert!(is_balanced(acc, s));
}

/// Returns true iff `q == k*p + s*G`.
pub fn is_scaled_eq(q: Point, k: Scalar, p: Point, s: Scalar) -> bool {
jet::gej_ge_equiv(jet::linear_combination_1((k, point_to_gej(p)), s), point_to_ge(q))
}

/// Asserts that `q == k*p + s*G`.
pub fn assert_scaled_eq(q: Point, k: Scalar, p: Point, s: Scalar,) {
jet::point_verify_1(((k, p), s), q);
}

/// Returns true iff `p == q + s*G`.
pub fn is_value_eq(p: Point, q: Point, s: Scalar) -> bool {
is_scaled_eq(q, 1, p, s)
}

/// Asserts that `p == q + s*G`, i.e. that two commitments hold the same value.
pub fn assert_value_eq(p: Point, q: Point, s: Scalar) {
assert_scaled_eq(q, 1, p, s);
}

/// Asserts that `a*x == b*y + s*G`.
pub fn assert_ratio_eq(a: Scalar, x: Point, b: Scalar, y: Point, s: Scalar) {
assert_balanced(sub_scaled(add_scaled(zero(), a, x), b, y), s);
}

/// Asserts that `c1 + c2 == c_sum + s*G`.
pub fn assert_sum_eq(c1: Point, c2: Point, c_sum: Point, s: Scalar) {
assert_balanced(sub(add(add(zero(), c1), c2), c_sum), s);
}
9 changes: 8 additions & 1 deletion simf/lib/secp256k1/operations.simf
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ pub fn ge_to_point(p: Ge) -> Point {
}
}

/// Decompress a `Point` into affine coordinates.
/// Panics if `jet::decompress(p)` returns `None`.
pub fn point_to_ge(p: Point) -> Ge {
unwrap(jet::decompress(p))
}

/// Decompress a `Point` into a Jacobian point with `z = 1`.
/// Panics if `jet::decompress(p)` returns `None`.
pub fn point_to_gej(p: Point) -> Gej {
(unwrap(jet::decompress(p)), 1)
(point_to_ge(p), 1)
}

/// Convert the point into affine coordinates.
Expand Down
42 changes: 42 additions & 0 deletions simf/lib/u1/convert.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/// Widening uint conversions

/// Converts u1 to u8
pub fn u1_to_u8(a: u1) -> u8 {
jet::left_pad_low_1_8(a)
}

/// Converts u1 to u16
pub fn u1_to_u16(a: u1) -> u16 {
jet::left_pad_low_1_16(a)
}

/// Converts u1 to u32
pub fn u1_to_u32(a: u1) -> u32 {
jet::left_pad_low_1_32(a)
}

/// Converts u1 to u64
pub fn u1_to_u64(a: u1) -> u64 {
jet::left_pad_low_1_64(a)
}

/// Converts u1 to u128
pub fn u1_to_u128(a: u1) -> u128 {
let a_u64: u64 = u1_to_u64(a);

<(u64, u64)>::into((0, a_u64))
}

/// Converts u1 to u256
pub fn u1_to_u256(a: u1) -> u256 {
let a_u128: u128 = u1_to_u128(a);

<(u128, u128)>::into((0, a_u128))
}

/// Type conversions

/// Converts u1 to bool
pub fn u1_to_bool(a: u1) -> bool {
<u1>::into(a)
}
49 changes: 49 additions & 0 deletions simf/lib/u8/convert.simf
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/// Widening uint conversions

/// Converts u8 to u16
pub fn u8_to_u16(a: u8) -> u16 {
jet::left_pad_low_8_16(a)
}

/// Converts u8 to u32
pub fn u8_to_u32(a: u8) -> u32 {
jet::left_pad_low_8_32(a)
}

/// Converts u8 to u64
pub fn u8_to_u64(a: u8) -> u64 {
jet::left_pad_low_8_64(a)
}

/// Converts u8 to u128
pub fn u8_to_u128(a: u8) -> u128 {
let a_u64: u64 = u8_to_u64(a);

<(u64, u64)>::into((0, a_u64))
}

/// Converts u8 to u256
pub fn u8_to_u256(a: u8) -> u256 {
let a_u128: u128 = u8_to_u128(a);

<(u128, u128)>::into((0, a_u128))
}

/// Splitting uint conversions

/// Splits u8 into eight u1
pub fn split_u8_to_u1(a: u8) -> (u1, u1, u1, u1, u1, u1, u1, u1) {
<u8>::into(a)
}

/// Narrowing uint conversions

/// Converts u8 into u1.
/// Panics if the value does not fit in u1
pub fn safe_u8_to_u1(a: u8) -> u1 {
let u1_max: u8 = jet::left_pad_low_1_8(jet::high_1());

assert!(jet::le_8(a, u1_max));

jet::rightmost_8_1(a)
}
File renamed without changes.
Loading
Loading