diff --git a/src/lib.rs b/src/lib.rs index aa1e418..cbb1692 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -122,6 +122,12 @@ impl Point { } false } + pub fn zero() -> Point { + return Point { + x: Zero::zero(), + y: Zero::zero(), + }; + } } pub fn decompress_point(bb: [u8; 32]) -> Result { @@ -269,15 +275,99 @@ impl PrivateKey { // h = H(x, r, m) let pk = &self.public()?; - let h = schnorr_hash(&pk, m, &r)?; + let h = hash_sig(&pk, m, &r)?; // s= k+x·h let s = k + &self.key * &h; Ok((r, s)) } + + // https://eprint.iacr.org/2018/068.pdf + pub fn sign_aggr( + &self, + x: Point, + r: Point, + ri: BigInt, + l: Vec, + m: Vec, + ) -> Result { + let pk = &self.public()?; + // a0 = h(l, X0) + let ai = hash_agg(&l, pk)?; + + // c = H(x, r, m) + let c = hash_sig(&x, m, &r)?; + // s0 = r0 + c · a0 · sk0 mod p + let si = ri + c * ai * &self.key; + Ok(utils::modulus(&si, &Q)) + } +} +pub fn calc_ri() -> Result<(BigInt, Point), String> { + // random r + let mut rng = rand::thread_rng(); + let k = rng.gen_biguint(1024).to_bigint().unwrap(); + + // r = k·G + let r = B8.mul_scalar(&k)?; + Ok((k, r)) +} +pub fn aggr_pks(mut pks: Vec, ris: Vec) -> Result<(Point, Point, Vec), String> { + let mut pk_aggr: Vec = Vec::new(); + for i in 0..pks.len() { + pk_aggr.append(&mut pks[i].compress().to_vec()); + } + + // (Xi=pk) + // l = {X1, X2, X3, ...} + let l = pk_aggr.clone(); + + // X = sum{ h(l, Xi)·Xi } = sum{ Xi · ai } + // a0 = h(l, X0) + let ai = hash_agg(&l, &pks[0])?; + let mut x: Point = pks[0].mul_scalar(&ai)?; + for i in 1..pks.len() { + // ai = h(l, Xi) + let ai = hash_agg(&l, &pks[i])?; + // x = x + ai · xi; + let s = pks[i].mul_scalar(&ai)?; + x = x.add(&s)?; + } + + // r = sum{ ri } + let mut r: Point = ris[0].clone(); + for i in 1..ris.len() { + r = r.add(&ris[i])?; + } + + Ok((x, r, l)) +} +pub fn aggr_signatures(sigs: Vec) -> Result { + let mut s: BigInt = Zero::zero(); + for i in 0..sigs.len() { + // s = utils::modulus(&(s + &sigs[i]), &Q); + s = s + &sigs[i]; + } + Ok(utils::modulus(&s, &Q)) + // Ok(s) +} +pub fn verify_schnorr_aggregated( + x: Point, + r: Point, + s: BigInt, + m: Vec, +) -> Result { + // sG = s·G + let sg = B8.mul_scalar(&s)?; + + let c = hash_sig(&x, m, &r)?; + let x_c = x.mul_scalar(&c)?; + let right = r.add(&x_c)?; + println!("x:\n{:?}\n{:?}\n", sg.x.to_string(), right.x.to_string()); + println!("y:\n{:?}\n{:?}\n", sg.y.to_string(), right.y.to_string()); + Ok(sg.equals(right)) } -pub fn schnorr_hash(pk: &Point, m: Vec, c: &Point) -> Result { +pub fn hash_sig(pk: &Point, m: Vec, c: &Point) -> Result { let b: &mut Vec = &mut Vec::new(); // other option could be to do it without compressing the points, and concatenating x|y @@ -287,7 +377,17 @@ pub fn schnorr_hash(pk: &Point, m: Vec, c: &Point) -> Result let poseidon = Poseidon::new(); let h = poseidon.hash_bytes(b.to_vec())?; - println!("h {:?}", h.to_string()); + Ok(h) +} +pub fn hash_agg(l: &Vec, xi: &Point) -> Result { + let b: &mut Vec = &mut Vec::new(); + + // other option could be to do it without compressing the points, and concatenating x|y + b.append(&mut l.clone()); + b.append(&mut xi.compress().to_vec()); + + let poseidon = Poseidon::new(); + let h = poseidon.hash_bytes(b.to_vec())?; Ok(h) } @@ -296,11 +396,11 @@ pub fn verify_schnorr(pk: Point, m: Vec, r: Point, s: BigInt) -> Result PrivateKey { @@ -381,6 +481,7 @@ mod tests { extern crate rustc_hex; use rustc_hex::{FromHex, ToHex}; + /* #[test] fn test_add_same_point() { let p: Point = Point { @@ -654,4 +755,44 @@ mod tests { let verification = verify_schnorr(pk, msg, s, e).unwrap(); assert_eq!(true, verification); } + */ + #[test] + fn test_aggregated_schnorr_signature() { + let m: Vec = ("123456".to_owned() + &1.to_string()).as_bytes().to_vec(); + + let sk0 = new_key(); + let pk0 = sk0.public().unwrap(); + let sk1 = new_key(); + let pk1 = sk1.public().unwrap(); + let mut pks: Vec = Vec::new(); + pks.push(pk0.clone()); + pks.push(pk1.clone()); + + let (k0, r0) = calc_ri().unwrap(); + let (k1, r1) = calc_ri().unwrap(); + let mut ris: Vec = Vec::new(); + ris.push(r0); + ris.push(r1); + + // aggregate public keys + let (x, r, l) = aggr_pks(pks, ris).unwrap(); + + // perform the signs + let sig0 = sk0 + .sign_aggr(x.clone(), r.clone(), k0, l.clone(), m.clone()) + .unwrap(); + let sig1 = sk1 + .sign_aggr(x.clone(), r.clone(), k1, l.clone(), m.clone()) + .unwrap(); + + // aggregate the signatures + let mut sigs: Vec = Vec::new(); + sigs.push(sig0); + sigs.push(sig1); + let aggr_sig = aggr_signatures(sigs).unwrap(); + + // verify the pk with the aggregated signatures + let verification = verify_schnorr_aggregated(x, r, aggr_sig, m).unwrap(); + assert_eq!(true, verification); + } }