Implementation of Jubjub point representation.

This commit is contained in:
Sean Bowe 2018-02-24 14:11:01 -07:00
parent 4441a0da41
commit 3346fba915
No known key found for this signature in database
GPG Key ID: 95684257D8F8B031
5 changed files with 125 additions and 1 deletions

View File

@ -20,6 +20,9 @@ bellman = "0.0.8"
byteorder = "1"
[dev-dependencies]
hex-literal = "0.1"
[features]
default = ["u128-support"]
u128-support = ["pairing/u128-support"]

View File

@ -20,6 +20,12 @@ use rand::{
use std::marker::PhantomData;
use std::io::{
self,
Write,
Read
};
// Represents the affine point (X/Z, Y/Z) via the extended
// twisted Edwards coordinates.
pub struct Point<E: JubjubEngine, Subgroup> {
@ -80,7 +86,67 @@ impl<E: JubjubEngine, Subgroup> PartialEq for Point<E, Subgroup> {
}
}
fn swap_bits_u64(x: u64) -> u64
{
let mut tmp = 0;
for i in 0..64 {
tmp |= ((x >> i) & 1) << (63 - i);
}
tmp
}
#[test]
fn test_swap_bits_u64() {
assert_eq!(swap_bits_u64(17182120934178543809), 0b1000001100011011110000011000111000101111111001001100111001110111);
assert_eq!(swap_bits_u64(15135675916470734665), 0b1001001011110010001101010010001110110000100111010011000001001011);
assert_eq!(swap_bits_u64(6724233301461108393), 0b1001010101100000100011100001010111110001011000101000101010111010);
assert_eq!(swap_bits_u64(206708183275952289), 0b1000010100011010001010100011101011111111111110100111101101000000);
assert_eq!(swap_bits_u64(12712751566144824320), 0b0000000000100110010110111000001110001100001000110011011000001101);
let mut a = 15863238721320035327u64;
for _ in 0..1000 {
a = a.wrapping_mul(a);
let swapped = swap_bits_u64(a);
let unswapped = swap_bits_u64(swapped);
assert_eq!(a, unswapped);
}
}
impl<E: JubjubEngine> Point<E, Unknown> {
pub fn read<R: Read>(
reader: R,
params: &E::Params
) -> io::Result<Self>
{
let mut y_repr = <E::Fr as PrimeField>::Repr::default();
y_repr.read_be(reader)?;
y_repr.as_mut().reverse();
for b in y_repr.as_mut() {
*b = swap_bits_u64(*b);
}
let x_sign = (y_repr.as_ref()[3] >> 63) == 1;
y_repr.as_mut()[3] &= 0x7fffffffffffffff;
match E::Fr::from_repr(y_repr) {
Ok(y) => {
match Self::get_for_y(y, x_sign, params) {
Some(p) => Ok(p),
None => {
Err(io::Error::new(io::ErrorKind::InvalidInput, "not on curve"))
}
}
},
Err(_) => {
Err(io::Error::new(io::ErrorKind::InvalidInput, "y is not in field"))
}
}
}
pub fn get_for_y(y: E::Fr, sign: bool, params: &E::Params) -> Option<Self>
{
// Given a y on the curve, x^2 = (y^2 - 1) / (dy^2 + 1)
@ -151,6 +217,30 @@ impl<E: JubjubEngine> Point<E, Unknown> {
}
impl<E: JubjubEngine, Subgroup> Point<E, Subgroup> {
pub fn write<W: Write>(
&self,
writer: W
) -> io::Result<()>
{
let (x, y) = self.into_xy();
assert_eq!(E::Fr::NUM_BITS, 255);
let x_repr = x.into_repr();
let mut y_repr = y.into_repr();
if x_repr.is_odd() {
y_repr.as_mut()[3] |= 0x8000000000000000u64;
}
y_repr.as_mut().reverse();
for b in y_repr.as_mut() {
*b = swap_bits_u64(*b);
}
y_repr.write_be(writer)
}
/// Convert from a Montgomery point
pub fn from_montgomery(
m: &montgomery::Point<E, Subgroup>,

View File

@ -72,7 +72,8 @@ pub enum FixedGenerators {
ValueCommitmentValue = 2,
ValueCommitmentRandomness = 3,
NullifierPosition = 4,
Max = 5
SpendingKeyGenerator = 5,
Max = 6
}
pub struct JubjubBls12 {
@ -236,4 +237,14 @@ fn test_jubjub_bls12() {
let params = JubjubBls12::new();
tests::test_suite::<Bls12>(&params);
let test_repr = hex!("b9481dd1103b7d1f8578078eb429d3c476472f53e88c0eaefdf51334c7c8b98c");
let p = edwards::Point::<Bls12, _>::read(&test_repr[..], &params).unwrap();
let q = edwards::Point::<Bls12, _>::get_for_y(
Fr::from_str("22440861827555040311190986994816762244378363690614952020532787748720529117853").unwrap(),
false,
&params
).unwrap();
assert!(p == q);
}

View File

@ -26,6 +26,7 @@ pub fn test_suite<E: JubjubEngine>(params: &E::Params) {
test_order::<E>(params);
test_mul_associativity::<E>(params);
test_loworder::<E>(params);
test_read_write::<E>(params);
}
fn is_on_mont_curve<E: JubjubEngine, P: JubjubParams<E>>(
@ -245,6 +246,21 @@ fn test_get_for<E: JubjubEngine>(params: &E::Params) {
}
}
fn test_read_write<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
for _ in 0..1000 {
let e = edwards::Point::<E, _>::rand(rng, params);
let mut v = vec![];
e.write(&mut v).unwrap();
let e2 = edwards::Point::read(&v[..], params).unwrap();
assert!(e == e2);
}
}
fn test_rand<E: JubjubEngine>(params: &E::Params) {
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);

View File

@ -6,6 +6,10 @@ extern crate rand;
extern crate byteorder;
#[cfg(test)]
#[macro_use]
extern crate hex_literal;
pub mod jubjub;
pub mod circuit;
pub mod group_hash;