simfony 0.1.0

Rust-like language that compiles to Simplicity bytecode.
Documentation
/*
 * ESCROW WITH DELAY
 *
 * An escrow agent can approve the movement of coins in cooperation with the
 * sender or the recipient. The escrow agent cannot steal the coins for himself.
 * The sender can refund her coins after a timeout.
 *
 * https://docs.ivylang.org/bitcoin/language/ExampleContracts.html#escrowwithdelay
 */
fn not(bit: bool) -> bool {
    <u1>::into(jet::complement_1(<bool>::into(bit)))
}

fn checksig(pk: Pubkey, sig: Signature) {
    let msg: u256 = jet::sig_all_hash();
    jet::bip_0340_verify((pk, msg), sig);
}

fn checksig_add(counter: u8, pk: Pubkey, maybe_sig: Option<Signature>) -> u8 {
    match maybe_sig {
        Some(sig: Signature) => {
            checksig(pk, sig);
            let (carry, new_counter): (bool, u8) = jet::increment_8(counter);
            assert!(not(carry));
            new_counter
        }
        None => counter,
    }
}

fn check2of3multisig(pks: [Pubkey; 3], maybe_sigs: [Option<Signature>; 3]) {
    let [pk1, pk2, pk3]: [Pubkey; 3] = pks;
    let [sig1, sig2, sig3]: [Option<Signature>; 3] = maybe_sigs;

    let counter1: u8 = checksig_add(0, pk1, sig1);
    let counter2: u8 = checksig_add(counter1, pk2, sig2);
    let counter3: u8 = checksig_add(counter2, pk3, sig3);

    let threshold: u8 = 2;
    assert!(jet::eq_8(counter3, threshold));
}

fn transfer_spend(maybe_sigs: [Option<Signature>; 3]) {
    let sender_pk: Pubkey = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798; // 1 * G
    let recipient_pk: Pubkey = 0xc6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5; // 2 * G
    let escrow_pk: Pubkey = 0xf9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9; // 3 * G
    check2of3multisig([sender_pk, recipient_pk, escrow_pk], maybe_sigs);
}

fn timeout_spend(sender_sig: Signature) {
    let sender_pk: Pubkey = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798; // 1 * G
    checksig(sender_pk, sender_sig);
    let timeout: Distance = 1000;
    jet::check_lock_distance(timeout);
}

fn main() {
    match witness::TRANSFER_OR_TIMEOUT {
        Left(maybe_sigs: [Option<Signature>; 3]) => transfer_spend(maybe_sigs),
        Right(sender_sig: Signature) => timeout_spend(sender_sig),
    }
}