constant "Opcodes" {
	EcFixedPointShort VALUE_COMMIT_VALUE,
	EcFixedPoint VALUE_COMMIT_RANDOM,
	EcFixedPointBase NULLIFIER_K,
}

witness "Opcodes" {
	Base value,
	Scalar value_blind,

	Base blind,

	Base a,
	Base b,

	Base secret,

	EcNiPoint pubkey,
	Base ephem_secret,

	Uint32 leaf_pos,
	MerklePath path,

	Base cond,
}

circuit "Opcodes" {
	vcv = ec_mul_short(value, VALUE_COMMIT_VALUE);
	vcr = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
	value_commit = ec_add(vcv, vcr);
	value_commit_x = ec_get_x(value_commit);
	value_commit_y = ec_get_y(value_commit);
	constrain_instance(ec_get_x(value_commit));
	constrain_instance(ec_get_y(value_commit));

	vcv2 = ec_mul_short(value, VALUE_COMMIT_VALUE);
	vcr2 = ec_mul(value_blind, VALUE_COMMIT_RANDOM);
	value_commit2 = ec_add(vcv2, vcr2);
	constrain_equal_point(value_commit, value_commit2);

	one = witness_base(1);
	two = witness_base(2);
	c = poseidon_hash(one, two, blind);
	constrain_instance(c);

	d = poseidon_hash(one, blind, ec_get_x(value_commit), ec_get_y(value_commit));
	constrain_instance(d);

	d2 = poseidon_hash(one, blind, ec_get_x(value_commit2), ec_get_y(value_commit2));
	constrain_equal_base(d, d2);

	range_check(64, a);
	range_check(253, b);
	less_than_strict(a, b);
	less_than_loose(a, b);

	root = merkle_root(leaf_pos, path, c);
	constrain_instance(root);

	public = ec_mul_base(secret, NULLIFIER_K);
	constrain_instance(ec_get_x(public));
	constrain_instance(ec_get_y(public));

	bool_check(one);

	ephem_public = ec_mul_var_base(ephem_secret, pubkey);
	constrain_instance(ec_get_x(ephem_public));
	constrain_instance(ec_get_y(ephem_public));

	out = cond_select(cond, a, b);
	constrain_instance(out);
}
