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
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);
}
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
Loading