Added G1/G2/Fq2 serialization and test vectors.
This commit is contained in:
parent
cb2ff5c1ad
commit
b05ecd3bb0
|
@ -2,6 +2,8 @@ use fields::{FieldElement, const_fp, Fq};
|
||||||
use std::ops::{Add, Sub, Mul, Neg};
|
use std::ops::{Add, Sub, Mul, Neg};
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
|
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn non_residue() -> Fq {
|
fn non_residue() -> Fq {
|
||||||
// (q - 1) is a quadratic nonresidue in Fq
|
// (q - 1) is a quadratic nonresidue in Fq
|
||||||
|
@ -15,6 +17,26 @@ pub struct Fq2 {
|
||||||
c1: Fq
|
c1: Fq
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Encodable for Fq2 {
|
||||||
|
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||||
|
// TODO: multiply c0 and c1 during encoding
|
||||||
|
try!(self.c0.encode(s));
|
||||||
|
try!(self.c1.encode(s));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Decodable for Fq2 {
|
||||||
|
fn decode<S: Decoder>(s: &mut S) -> Result<Fq2, S::Error> {
|
||||||
|
// TODO: divrem to get c0 and c1
|
||||||
|
let c0 = try!(Fq::decode(s));
|
||||||
|
let c1 = try!(Fq::decode(s));
|
||||||
|
|
||||||
|
Ok(Fq2::new(c0, c1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Fq2 {
|
impl Fq2 {
|
||||||
pub fn new(c0: Fq, c1: Fq) -> Self {
|
pub fn new(c0: Fq, c1: Fq) -> Self {
|
||||||
Fq2 {
|
Fq2 {
|
||||||
|
@ -22,6 +44,13 @@ impl Fq2 {
|
||||||
c1: c1
|
c1: c1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn scale(&self, by: Fq) -> Self {
|
||||||
|
Fq2 {
|
||||||
|
c0: self.c0 * by,
|
||||||
|
c1: self.c1 * by
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FieldElement for Fq2 {
|
impl FieldElement for Fq2 {
|
||||||
|
|
|
@ -4,6 +4,8 @@ use arith::U256;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
|
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||||
|
|
||||||
pub trait GroupElement: Sized +
|
pub trait GroupElement: Sized +
|
||||||
Copy +
|
Copy +
|
||||||
Clone +
|
Clone +
|
||||||
|
@ -23,36 +25,42 @@ pub trait GroupElement: Sized +
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait GroupParams: Sized {
|
pub trait GroupParams: Sized {
|
||||||
type Base: FieldElement;
|
type Base: FieldElement + Decodable + Encodable;
|
||||||
|
|
||||||
fn name() -> &'static str;
|
fn name() -> &'static str;
|
||||||
fn one() -> Jacobian<Self>;
|
fn one() -> G<Self>;
|
||||||
|
fn coeff_b() -> Self::Base;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Jacobian<P: GroupParams> {
|
pub struct G<P: GroupParams> {
|
||||||
x: P::Base,
|
x: P::Base,
|
||||||
y: P::Base,
|
y: P::Base,
|
||||||
z: P::Base
|
z: P::Base
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: GroupParams> fmt::Debug for Jacobian<P> {
|
pub struct AffineG<P: GroupParams> {
|
||||||
|
x: P::Base,
|
||||||
|
y: P::Base
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: GroupParams> fmt::Debug for G<P> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}({:?}, {:?}, {:?})", P::name(), self.x, self.y, self.z)
|
write!(f, "{}({:?}, {:?}, {:?})", P::name(), self.x, self.y, self.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: GroupParams> Clone for Jacobian<P> {
|
impl<P: GroupParams> Clone for G<P> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Jacobian {
|
G {
|
||||||
x: self.x,
|
x: self.x,
|
||||||
y: self.y,
|
y: self.y,
|
||||||
z: self.z
|
z: self.z
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<P: GroupParams> Copy for Jacobian<P> {}
|
impl<P: GroupParams> Copy for G<P> {}
|
||||||
|
|
||||||
impl<P: GroupParams> PartialEq for Jacobian<P> {
|
impl<P: GroupParams> PartialEq for G<P> {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
if self.is_zero() {
|
if self.is_zero() {
|
||||||
return other.is_zero()
|
return other.is_zero()
|
||||||
|
@ -79,11 +87,81 @@ impl<P: GroupParams> PartialEq for Jacobian<P> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<P: GroupParams> Eq for Jacobian<P> { }
|
impl<P: GroupParams> Eq for G<P> { }
|
||||||
|
|
||||||
impl<P: GroupParams> GroupElement for Jacobian<P> {
|
impl<P: GroupParams> G<P> {
|
||||||
|
fn to_affine(&self) -> Option<AffineG<P>> {
|
||||||
|
if self.z.is_zero() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let zinv = self.z.inverse().unwrap();
|
||||||
|
let zinv_squared = zinv.squared();
|
||||||
|
|
||||||
|
Some(AffineG {
|
||||||
|
x: self.x * zinv_squared,
|
||||||
|
y: self.y * (zinv_squared * zinv)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: GroupParams> AffineG<P> {
|
||||||
|
fn to_jacobian(&self) -> G<P> {
|
||||||
|
G {
|
||||||
|
x: self.x,
|
||||||
|
y: self.y,
|
||||||
|
z: P::Base::one()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: GroupParams> Encodable for G<P> {
|
||||||
|
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||||
|
match self.to_affine() {
|
||||||
|
None => {
|
||||||
|
let l: u8 = 0;
|
||||||
|
try!(l.encode(s));
|
||||||
|
},
|
||||||
|
Some(p) => {
|
||||||
|
let l: u8 = 4;
|
||||||
|
try!(l.encode(s));
|
||||||
|
try!(p.x.encode(s));
|
||||||
|
try!(p.y.encode(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: GroupParams> Decodable for G<P> {
|
||||||
|
fn decode<S: Decoder>(s: &mut S) -> Result<G<P>, S::Error> {
|
||||||
|
let l = try!(u8::decode(s));
|
||||||
|
if l == 0 {
|
||||||
|
Ok(G::zero())
|
||||||
|
} else if l == 4 {
|
||||||
|
let x = try!(P::Base::decode(s));
|
||||||
|
let y = try!(P::Base::decode(s));
|
||||||
|
|
||||||
|
// y^2 = x^3 + b
|
||||||
|
if y.squared() == (x.squared() * x) + P::coeff_b() {
|
||||||
|
Ok(G {
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
z: P::Base::one()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(s.error("point is not on the curve"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(s.error("invalid leading byte for uncompressed group element"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<P: GroupParams> GroupElement for G<P> {
|
||||||
fn zero() -> Self {
|
fn zero() -> Self {
|
||||||
Jacobian {
|
G {
|
||||||
x: P::Base::zero(),
|
x: P::Base::zero(),
|
||||||
y: P::Base::one(),
|
y: P::Base::one(),
|
||||||
z: P::Base::zero()
|
z: P::Base::zero()
|
||||||
|
@ -116,7 +194,7 @@ impl<P: GroupParams> GroupElement for Jacobian<P> {
|
||||||
eight_c = eight_c + eight_c;
|
eight_c = eight_c + eight_c;
|
||||||
let y1z1 = self.y * self.z;
|
let y1z1 = self.y * self.z;
|
||||||
|
|
||||||
Jacobian {
|
G {
|
||||||
x: x3,
|
x: x3,
|
||||||
y: e * (d - x3) - eight_c,
|
y: e * (d - x3) - eight_c,
|
||||||
z: y1z1 + y1z1
|
z: y1z1 + y1z1
|
||||||
|
@ -124,11 +202,11 @@ impl<P: GroupParams> GroupElement for Jacobian<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: GroupParams> Mul<Fr> for Jacobian<P> {
|
impl<P: GroupParams> Mul<Fr> for G<P> {
|
||||||
type Output = Jacobian<P>;
|
type Output = G<P>;
|
||||||
|
|
||||||
fn mul(self, other: Fr) -> Jacobian<P> {
|
fn mul(self, other: Fr) -> G<P> {
|
||||||
let mut res = Jacobian::zero();
|
let mut res = G::zero();
|
||||||
let mut found_one = false;
|
let mut found_one = false;
|
||||||
|
|
||||||
for i in U256::from(other).bits() {
|
for i in U256::from(other).bits() {
|
||||||
|
@ -146,10 +224,10 @@ impl<P: GroupParams> Mul<Fr> for Jacobian<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: GroupParams> Add<Jacobian<P>> for Jacobian<P> {
|
impl<P: GroupParams> Add<G<P>> for G<P> {
|
||||||
type Output = Jacobian<P>;
|
type Output = G<P>;
|
||||||
|
|
||||||
fn add(self, other: Jacobian<P>) -> Jacobian<P> {
|
fn add(self, other: G<P>) -> G<P> {
|
||||||
if self.is_zero() {
|
if self.is_zero() {
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
@ -179,7 +257,7 @@ impl<P: GroupParams> Add<Jacobian<P>> for Jacobian<P> {
|
||||||
let s1_j = s1 * j;
|
let s1_j = s1 * j;
|
||||||
let x3 = r.squared() - j - (v + v);
|
let x3 = r.squared() - j - (v + v);
|
||||||
|
|
||||||
Jacobian {
|
G {
|
||||||
x: x3,
|
x: x3,
|
||||||
y: r * (v - x3) - (s1_j + s1_j),
|
y: r * (v - x3) - (s1_j + s1_j),
|
||||||
z: ((self.z + other.z).squared() - z1_squared - z2_squared) * h
|
z: ((self.z + other.z).squared() - z1_squared - z2_squared) * h
|
||||||
|
@ -188,11 +266,11 @@ impl<P: GroupParams> Add<Jacobian<P>> for Jacobian<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: GroupParams> Neg for Jacobian<P> {
|
impl<P: GroupParams> Neg for G<P> {
|
||||||
type Output = Jacobian<P>;
|
type Output = G<P>;
|
||||||
|
|
||||||
fn neg(self) -> Jacobian<P> {
|
fn neg(self) -> G<P> {
|
||||||
Jacobian {
|
G {
|
||||||
x: self.x,
|
x: self.x,
|
||||||
y: -self.y,
|
y: -self.y,
|
||||||
z: self.z
|
z: self.z
|
||||||
|
@ -200,10 +278,10 @@ impl<P: GroupParams> Neg for Jacobian<P> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P: GroupParams> Sub<Jacobian<P>> for Jacobian<P> {
|
impl<P: GroupParams> Sub<G<P>> for G<P> {
|
||||||
type Output = Jacobian<P>;
|
type Output = G<P>;
|
||||||
|
|
||||||
fn sub(self, other: Jacobian<P>) -> Jacobian<P> {
|
fn sub(self, other: G<P>) -> G<P> {
|
||||||
self + (-other)
|
self + (-other)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,16 +293,20 @@ impl GroupParams for G1Params {
|
||||||
|
|
||||||
fn name() -> &'static str { "G1" }
|
fn name() -> &'static str { "G1" }
|
||||||
|
|
||||||
fn one() -> Jacobian<Self> {
|
fn one() -> G<Self> {
|
||||||
Jacobian {
|
G {
|
||||||
x: Fq::one(),
|
x: Fq::one(),
|
||||||
y: const_fp([0xa6ba871b8b1e1b3a, 0x14f1d651eb8e167b, 0xccdd46def0f28c58, 0x1c14ef83340fbe5e]),
|
y: const_fp([0xa6ba871b8b1e1b3a, 0x14f1d651eb8e167b, 0xccdd46def0f28c58, 0x1c14ef83340fbe5e]),
|
||||||
z: Fq::one()
|
z: Fq::one()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn coeff_b() -> Fq {
|
||||||
|
const_fp([0x7a17caa950ad28d7, 0x1f6ac17ae15521b9, 0x334bea4e696bd284, 0x2a1f6744ce179d8e])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type G1 = Jacobian<G1Params>;
|
pub type G1 = G<G1Params>;
|
||||||
|
|
||||||
pub struct G2Params;
|
pub struct G2Params;
|
||||||
|
|
||||||
|
@ -233,16 +315,29 @@ impl GroupParams for G2Params {
|
||||||
|
|
||||||
fn name() -> &'static str { "G2" }
|
fn name() -> &'static str { "G2" }
|
||||||
|
|
||||||
fn one() -> Jacobian<Self> {
|
fn one() -> G<Self> {
|
||||||
Jacobian {
|
G {
|
||||||
x: Fq2::new(const_fp([0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b]), const_fp([0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b])),
|
x: Fq2::new(
|
||||||
y: Fq2::new(const_fp([0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206]), const_fp([0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482])),
|
const_fp([0x8e83b5d102bc2026, 0xdceb1935497b0172, 0xfbb8264797811adf, 0x19573841af96503b]),
|
||||||
|
const_fp([0xafb4737da84c6140, 0x6043dd5a5802d8c4, 0x09e950fc52a02f86, 0x14fef0833aea7b6b])
|
||||||
|
),
|
||||||
|
y: Fq2::new(
|
||||||
|
const_fp([0x619dfa9d886be9f6, 0xfe7fd297f59e9b78, 0xff9e1a62231b7dfe, 0x28fd7eebae9e4206]),
|
||||||
|
const_fp([0x64095b56c71856ee, 0xdc57f922327d3cbb, 0x55f935be33351076, 0x0da4a0e693fd6482])
|
||||||
|
),
|
||||||
z: Fq2::one()
|
z: Fq2::one()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn coeff_b() -> Fq2 {
|
||||||
|
Fq2::new(
|
||||||
|
const_fp([0x3bf938e377b802a8, 0x020b1b273633535d, 0x26b7edf049755260, 0x2514c6324384a86d]),
|
||||||
|
const_fp([0x38e7ecccd1dcff67, 0x65f0b37d93ce0d3e, 0xd749d0dd22ac00aa, 0x0141b9ce4a688d4d])
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type G2 = Jacobian<G2Params>;
|
pub type G2 = G<G2Params>;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -256,3 +351,27 @@ fn test_g1() {
|
||||||
fn test_g2() {
|
fn test_g2() {
|
||||||
tests::group_trials::<G2>();
|
tests::group_trials::<G2>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_affine_jacobian_conversion() {
|
||||||
|
let rng = &mut ::rand::thread_rng();
|
||||||
|
|
||||||
|
assert!(G1::zero().to_affine().is_none());
|
||||||
|
assert!(G2::zero().to_affine().is_none());
|
||||||
|
|
||||||
|
for _ in 0..1000 {
|
||||||
|
let a = G1::one() * Fr::random(rng);
|
||||||
|
let b = a.to_affine().unwrap();
|
||||||
|
let c = b.to_jacobian();
|
||||||
|
|
||||||
|
assert_eq!(a, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
for _ in 0..1000 {
|
||||||
|
let a = G2::one() * Fr::random(rng);
|
||||||
|
let b = a.to_affine().unwrap();
|
||||||
|
let c = b.to_jacobian();
|
||||||
|
|
||||||
|
assert_eq!(a, c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue