Initial commit
This commit is contained in:
267
src/tests/curve.rs
Normal file
267
src/tests/curve.rs
Normal file
@@ -0,0 +1,267 @@
|
||||
use rand::{SeedableRng, XorShiftRng, Rand};
|
||||
|
||||
use ::{CurveProjective, CurveAffine, Field};
|
||||
|
||||
pub fn curve_tests<G: CurveProjective>()
|
||||
{
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
// Negation edge case with zero.
|
||||
{
|
||||
let mut z = G::zero();
|
||||
z.negate();
|
||||
assert!(z.is_zero());
|
||||
}
|
||||
|
||||
// Doubling edge case with zero.
|
||||
{
|
||||
let mut z = G::zero();
|
||||
z.double();
|
||||
assert!(z.is_zero());
|
||||
}
|
||||
|
||||
// Addition edge cases with zero
|
||||
{
|
||||
let mut r = G::rand(&mut rng);
|
||||
let rcopy = r;
|
||||
r.add_assign(&G::zero());
|
||||
assert_eq!(r, rcopy);
|
||||
r.add_assign_mixed(&G::Affine::zero());
|
||||
assert_eq!(r, rcopy);
|
||||
|
||||
let mut z = G::zero();
|
||||
z.add_assign(&G::zero());
|
||||
assert!(z.is_zero());
|
||||
z.add_assign_mixed(&G::Affine::zero());
|
||||
assert!(z.is_zero());
|
||||
|
||||
let mut z2 = z;
|
||||
z2.add_assign(&r);
|
||||
|
||||
z.add_assign_mixed(&r.to_affine());
|
||||
|
||||
assert_eq!(z, z2);
|
||||
assert_eq!(z, r);
|
||||
}
|
||||
|
||||
// Transformations
|
||||
{
|
||||
let a = G::rand(&mut rng);
|
||||
let b = a.to_affine().to_projective();
|
||||
let c = a.to_affine().to_projective().to_affine().to_projective();
|
||||
assert_eq!(a, b);
|
||||
assert_eq!(b, c);
|
||||
}
|
||||
|
||||
random_addition_tests::<G>();
|
||||
random_multiplication_tests::<G>();
|
||||
random_doubling_tests::<G>();
|
||||
random_negation_tests::<G>();
|
||||
random_transformation_tests::<G>();
|
||||
}
|
||||
|
||||
fn random_negation_tests<G: CurveProjective>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let r = G::rand(&mut rng);
|
||||
|
||||
let s = G::Scalar::rand(&mut rng);
|
||||
let mut sneg = s;
|
||||
sneg.negate();
|
||||
|
||||
let mut t1 = r;
|
||||
t1.mul_assign(s);
|
||||
|
||||
let mut t2 = r;
|
||||
t2.mul_assign(sneg);
|
||||
|
||||
let mut t3 = t1;
|
||||
t3.add_assign(&t2);
|
||||
assert!(t3.is_zero());
|
||||
|
||||
let mut t4 = t1;
|
||||
t4.add_assign_mixed(&t2.to_affine());
|
||||
assert!(t4.is_zero());
|
||||
|
||||
t1.negate();
|
||||
assert_eq!(t1, t2);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_doubling_tests<G: CurveProjective>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut a = G::rand(&mut rng);
|
||||
let mut b = G::rand(&mut rng);
|
||||
|
||||
// 2(a + b)
|
||||
let mut tmp1 = a;
|
||||
tmp1.add_assign(&b);
|
||||
tmp1.double();
|
||||
|
||||
// 2a + 2b
|
||||
a.double();
|
||||
b.double();
|
||||
|
||||
let mut tmp2 = a;
|
||||
tmp2.add_assign(&b);
|
||||
|
||||
let mut tmp3 = a;
|
||||
tmp3.add_assign_mixed(&b.to_affine());
|
||||
|
||||
assert_eq!(tmp1, tmp2);
|
||||
assert_eq!(tmp1, tmp3);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_multiplication_tests<G: CurveProjective>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let mut a = G::rand(&mut rng);
|
||||
let mut b = G::rand(&mut rng);
|
||||
let a_affine = a.to_affine();
|
||||
let b_affine = b.to_affine();
|
||||
|
||||
let s = G::Scalar::rand(&mut rng);
|
||||
|
||||
// s ( a + b )
|
||||
let mut tmp1 = a;
|
||||
tmp1.add_assign(&b);
|
||||
tmp1.mul_assign(s);
|
||||
|
||||
// sa + sb
|
||||
a.mul_assign(s);
|
||||
b.mul_assign(s);
|
||||
|
||||
let mut tmp2 = a;
|
||||
tmp2.add_assign(&b);
|
||||
|
||||
// Affine multiplication
|
||||
let mut tmp3 = a_affine.mul(s);
|
||||
tmp3.add_assign(&b_affine.mul(s));
|
||||
|
||||
assert_eq!(tmp1, tmp2);
|
||||
assert_eq!(tmp1, tmp3);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_addition_tests<G: CurveProjective>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let a = G::rand(&mut rng);
|
||||
let b = G::rand(&mut rng);
|
||||
let c = G::rand(&mut rng);
|
||||
let a_affine = a.to_affine();
|
||||
let b_affine = b.to_affine();
|
||||
let c_affine = c.to_affine();
|
||||
|
||||
// a + a should equal the doubling
|
||||
{
|
||||
let mut aplusa = a;
|
||||
aplusa.add_assign(&a);
|
||||
|
||||
let mut aplusamixed = a;
|
||||
aplusamixed.add_assign_mixed(&a.to_affine());
|
||||
|
||||
let mut adouble = a;
|
||||
adouble.double();
|
||||
|
||||
assert_eq!(aplusa, adouble);
|
||||
assert_eq!(aplusa, aplusamixed);
|
||||
}
|
||||
|
||||
let mut tmp = vec![G::zero(); 6];
|
||||
|
||||
// (a + b) + c
|
||||
tmp[0] = a;
|
||||
tmp[0].add_assign(&b);
|
||||
tmp[0].add_assign(&c);
|
||||
|
||||
// a + (b + c)
|
||||
tmp[1] = b;
|
||||
tmp[1].add_assign(&c);
|
||||
tmp[1].add_assign(&a);
|
||||
|
||||
// (a + c) + b
|
||||
tmp[2] = a;
|
||||
tmp[2].add_assign(&c);
|
||||
tmp[2].add_assign(&b);
|
||||
|
||||
// Mixed addition
|
||||
|
||||
// (a + b) + c
|
||||
tmp[3] = a_affine.to_projective();
|
||||
tmp[3].add_assign_mixed(&b_affine);
|
||||
tmp[3].add_assign_mixed(&c_affine);
|
||||
|
||||
// a + (b + c)
|
||||
tmp[4] = b_affine.to_projective();
|
||||
tmp[4].add_assign_mixed(&c_affine);
|
||||
tmp[4].add_assign_mixed(&a_affine);
|
||||
|
||||
// (a + c) + b
|
||||
tmp[5] = a_affine.to_projective();
|
||||
tmp[5].add_assign_mixed(&c_affine);
|
||||
tmp[5].add_assign_mixed(&b_affine);
|
||||
|
||||
// Comparisons
|
||||
for i in 0..6 {
|
||||
for j in 0..6 {
|
||||
assert_eq!(tmp[i], tmp[j]);
|
||||
assert_eq!(tmp[i].to_affine(), tmp[j].to_affine());
|
||||
}
|
||||
|
||||
assert!(tmp[i] != a);
|
||||
assert!(tmp[i] != b);
|
||||
assert!(tmp[i] != c);
|
||||
|
||||
assert!(a != tmp[i]);
|
||||
assert!(b != tmp[i]);
|
||||
assert!(c != tmp[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn random_transformation_tests<G: CurveProjective>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let g = G::rand(&mut rng);
|
||||
let g_affine = g.to_affine();
|
||||
let g_projective = g_affine.to_projective();
|
||||
assert_eq!(g, g_projective);
|
||||
}
|
||||
|
||||
// Batch normalization
|
||||
for _ in 0..10 {
|
||||
let mut v = (0..1000).map(|_| G::rand(&mut rng)).collect::<Vec<_>>();
|
||||
|
||||
for i in &v {
|
||||
assert!(!i.is_normalized());
|
||||
}
|
||||
|
||||
use rand::distributions::{IndependentSample, Range};
|
||||
let between = Range::new(0, 1000);
|
||||
// Sprinkle in some normalized points
|
||||
for _ in 0..5 {
|
||||
v[between.ind_sample(&mut rng)] = G::zero();
|
||||
}
|
||||
for _ in 0..5 {
|
||||
let s = between.ind_sample(&mut rng);
|
||||
v[s] = v[s].to_affine().to_projective();
|
||||
}
|
||||
|
||||
let expected_v = v.iter().map(|v| v.to_affine().to_projective()).collect::<Vec<_>>();
|
||||
G::batch_normalization(&mut v);
|
||||
|
||||
for i in &v {
|
||||
assert!(i.is_normalized());
|
||||
}
|
||||
|
||||
assert_eq!(v, expected_v);
|
||||
}
|
||||
}
|
||||
120
src/tests/engine.rs
Normal file
120
src/tests/engine.rs
Normal file
@@ -0,0 +1,120 @@
|
||||
use rand::{SeedableRng, XorShiftRng, Rand};
|
||||
|
||||
use ::{Engine, CurveProjective, CurveAffine, Field, PrimeField};
|
||||
|
||||
pub fn engine_tests<E: Engine>()
|
||||
{
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let z1 = E::G1Affine::zero().prepare();
|
||||
let z2 = E::G2Affine::zero().prepare();
|
||||
|
||||
let a = E::G1::rand(&mut rng).to_affine().prepare();
|
||||
let b = E::G2::rand(&mut rng).to_affine().prepare();
|
||||
let c = E::G1::rand(&mut rng).to_affine().prepare();
|
||||
let d = E::G2::rand(&mut rng).to_affine().prepare();
|
||||
|
||||
assert_eq!(
|
||||
E::Fqk::one(),
|
||||
E::final_exponentiation(&E::miller_loop(&[(&z1, &b)])).unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
E::Fqk::one(),
|
||||
E::final_exponentiation(&E::miller_loop(&[(&a, &z2)])).unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
E::final_exponentiation(&E::miller_loop(&[(&z1, &b), (&c, &d)])).unwrap(),
|
||||
E::final_exponentiation(&E::miller_loop(&[(&a, &z2), (&c, &d)])).unwrap()
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&z1, &d)])).unwrap(),
|
||||
E::final_exponentiation(&E::miller_loop(&[(&a, &b), (&c, &z2)])).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
random_bilinearity_tests::<E>();
|
||||
random_miller_loop_tests::<E>();
|
||||
}
|
||||
|
||||
fn random_miller_loop_tests<E: Engine>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
// Exercise the miller loop for a reduced pairing
|
||||
for _ in 0..1000 {
|
||||
let a = E::G1::rand(&mut rng);
|
||||
let b = E::G2::rand(&mut rng);
|
||||
|
||||
let p2 = E::pairing(a, b);
|
||||
|
||||
let a = a.to_affine().prepare();
|
||||
let b = b.to_affine().prepare();
|
||||
|
||||
let p1 = E::final_exponentiation(&E::miller_loop(&[(&a, &b)])).unwrap();
|
||||
|
||||
assert_eq!(p1, p2);
|
||||
}
|
||||
|
||||
// Exercise a double miller loop
|
||||
for _ in 0..1000 {
|
||||
let a = E::G1::rand(&mut rng);
|
||||
let b = E::G2::rand(&mut rng);
|
||||
let c = E::G1::rand(&mut rng);
|
||||
let d = E::G2::rand(&mut rng);
|
||||
|
||||
let ab = E::pairing(a, b);
|
||||
let cd = E::pairing(c, d);
|
||||
|
||||
let mut abcd = ab;
|
||||
abcd.mul_assign(&cd);
|
||||
|
||||
let a = a.to_affine().prepare();
|
||||
let b = b.to_affine().prepare();
|
||||
let c = c.to_affine().prepare();
|
||||
let d = d.to_affine().prepare();
|
||||
|
||||
let abcd_with_double_loop = E::final_exponentiation(
|
||||
&E::miller_loop(&[(&a, &b), (&c, &d)])
|
||||
).unwrap();
|
||||
|
||||
assert_eq!(abcd, abcd_with_double_loop);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_bilinearity_tests<E: Engine>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..1000 {
|
||||
let a = E::G1::rand(&mut rng);
|
||||
let b = E::G2::rand(&mut rng);
|
||||
|
||||
let c = E::Fr::rand(&mut rng);
|
||||
let d = E::Fr::rand(&mut rng);
|
||||
|
||||
let mut ac = a;
|
||||
ac.mul_assign(c);
|
||||
|
||||
let mut ad = a;
|
||||
ad.mul_assign(d);
|
||||
|
||||
let mut bc = b;
|
||||
bc.mul_assign(c);
|
||||
|
||||
let mut bd = b;
|
||||
bd.mul_assign(d);
|
||||
|
||||
let acbd = E::pairing(ac, bd);
|
||||
let adbc = E::pairing(ad, bc);
|
||||
|
||||
let mut cd = c;
|
||||
cd.mul_assign(&d);
|
||||
|
||||
let abcd = E::pairing(a, b).pow(cd.into_repr());
|
||||
|
||||
assert_eq!(acbd, adbc);
|
||||
assert_eq!(acbd, abcd);
|
||||
}
|
||||
}
|
||||
229
src/tests/field.rs
Normal file
229
src/tests/field.rs
Normal file
@@ -0,0 +1,229 @@
|
||||
use rand::{Rng, SeedableRng, XorShiftRng};
|
||||
use ::{SqrtField, Field};
|
||||
|
||||
pub fn random_frobenius_tests<F: Field, C: AsRef<[u64]>>(characteristic: C, maxpower: usize) {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..100 {
|
||||
for i in 0..(maxpower+1) {
|
||||
let mut a = F::rand(&mut rng);
|
||||
let mut b = a;
|
||||
|
||||
for _ in 0..i {
|
||||
a = a.pow(&characteristic);
|
||||
}
|
||||
b.frobenius_map(i);
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn random_sqrt_tests<F: SqrtField>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(&mut rng);
|
||||
let mut b = a;
|
||||
b.square();
|
||||
|
||||
let b = b.sqrt().unwrap();
|
||||
let mut negb = b;
|
||||
negb.negate();
|
||||
|
||||
assert!(a == b || a == negb);
|
||||
}
|
||||
|
||||
let mut c = F::one();
|
||||
for _ in 0..10000 {
|
||||
let mut b = c;
|
||||
b.square();
|
||||
b = b.sqrt().unwrap();
|
||||
|
||||
if b != c {
|
||||
b.negate();
|
||||
}
|
||||
|
||||
assert_eq!(b, c);
|
||||
|
||||
c.add_assign(&F::one());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn random_field_tests<F: Field>() {
|
||||
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||
|
||||
random_multiplication_tests::<F, _>(&mut rng);
|
||||
random_addition_tests::<F, _>(&mut rng);
|
||||
random_subtraction_tests::<F, _>(&mut rng);
|
||||
random_negation_tests::<F, _>(&mut rng);
|
||||
random_doubling_tests::<F, _>(&mut rng);
|
||||
random_squaring_tests::<F, _>(&mut rng);
|
||||
random_inversion_tests::<F, _>(&mut rng);
|
||||
random_expansion_tests::<F, _>(&mut rng);
|
||||
|
||||
assert!(F::zero().is_zero());
|
||||
{
|
||||
let mut z = F::zero();
|
||||
z.negate();
|
||||
assert!(z.is_zero());
|
||||
}
|
||||
|
||||
assert!(F::zero().inverse().is_none());
|
||||
|
||||
// Multiplication by zero
|
||||
{
|
||||
let mut a = F::rand(&mut rng);
|
||||
a.mul_assign(&F::zero());
|
||||
assert!(a.is_zero());
|
||||
}
|
||||
|
||||
// Addition by zero
|
||||
{
|
||||
let mut a = F::rand(&mut rng);
|
||||
let copy = a;
|
||||
a.add_assign(&F::zero());
|
||||
assert_eq!(a, copy);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_multiplication_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(rng);
|
||||
let b = F::rand(rng);
|
||||
let c = F::rand(rng);
|
||||
|
||||
let mut t0 = a; // (a * b) * c
|
||||
t0.mul_assign(&b);
|
||||
t0.mul_assign(&c);
|
||||
|
||||
let mut t1 = a; // (a * c) * b
|
||||
t1.mul_assign(&c);
|
||||
t1.mul_assign(&b);
|
||||
|
||||
let mut t2 = b; // (b * c) * a
|
||||
t2.mul_assign(&c);
|
||||
t2.mul_assign(&a);
|
||||
|
||||
assert_eq!(t0, t1);
|
||||
assert_eq!(t1, t2);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_addition_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(rng);
|
||||
let b = F::rand(rng);
|
||||
let c = F::rand(rng);
|
||||
|
||||
let mut t0 = a; // (a + b) + c
|
||||
t0.add_assign(&b);
|
||||
t0.add_assign(&c);
|
||||
|
||||
let mut t1 = a; // (a + c) + b
|
||||
t1.add_assign(&c);
|
||||
t1.add_assign(&b);
|
||||
|
||||
let mut t2 = b; // (b + c) + a
|
||||
t2.add_assign(&c);
|
||||
t2.add_assign(&a);
|
||||
|
||||
assert_eq!(t0, t1);
|
||||
assert_eq!(t1, t2);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_subtraction_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(rng);
|
||||
let b = F::rand(rng);
|
||||
|
||||
let mut t0 = a; // (a - b)
|
||||
t0.sub_assign(&b);
|
||||
|
||||
let mut t1 = b; // (b - a)
|
||||
t1.sub_assign(&a);
|
||||
|
||||
let mut t2 = t0; // (a - b) + (b - a) = 0
|
||||
t2.add_assign(&t1);
|
||||
|
||||
assert!(t2.is_zero());
|
||||
}
|
||||
}
|
||||
|
||||
fn random_negation_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let a = F::rand(rng);
|
||||
let mut b = a;
|
||||
b.negate();
|
||||
b.add_assign(&a);
|
||||
|
||||
assert!(b.is_zero());
|
||||
}
|
||||
}
|
||||
|
||||
fn random_doubling_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let mut a = F::rand(rng);
|
||||
let mut b = a;
|
||||
a.add_assign(&b);
|
||||
b.double();
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_squaring_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
let mut a = F::rand(rng);
|
||||
let mut b = a;
|
||||
a.mul_assign(&b);
|
||||
b.square();
|
||||
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
fn random_inversion_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
assert!(F::zero().inverse().is_none());
|
||||
|
||||
for _ in 0..10000 {
|
||||
let mut a = F::rand(rng);
|
||||
let b = a.inverse().unwrap(); // probablistically nonzero
|
||||
a.mul_assign(&b);
|
||||
|
||||
assert_eq!(a, F::one());
|
||||
}
|
||||
}
|
||||
|
||||
fn random_expansion_tests<F: Field, R: Rng>(rng: &mut R) {
|
||||
for _ in 0..10000 {
|
||||
// Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d)
|
||||
|
||||
let a = F::rand(rng);
|
||||
let b = F::rand(rng);
|
||||
let c = F::rand(rng);
|
||||
let d = F::rand(rng);
|
||||
|
||||
let mut t0 = a;
|
||||
t0.add_assign(&b);
|
||||
let mut t1 = c;
|
||||
t1.add_assign(&d);
|
||||
t0.mul_assign(&t1);
|
||||
|
||||
let mut t2 = a;
|
||||
t2.mul_assign(&c);
|
||||
let mut t3 = b;
|
||||
t3.mul_assign(&c);
|
||||
let mut t4 = a;
|
||||
t4.mul_assign(&d);
|
||||
let mut t5 = b;
|
||||
t5.mul_assign(&d);
|
||||
|
||||
t2.add_assign(&t3);
|
||||
t2.add_assign(&t4);
|
||||
t2.add_assign(&t5);
|
||||
|
||||
assert_eq!(t0, t2);
|
||||
}
|
||||
}
|
||||
3
src/tests/mod.rs
Normal file
3
src/tests/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod curve;
|
||||
pub mod field;
|
||||
pub mod engine;
|
||||
Reference in New Issue
Block a user