mirror of
https://github.com/Qortal/pirate-librustzcash.git
synced 2025-02-12 10:05:47 +00:00
Implementation of group hash in the circuit.
This commit is contained in:
parent
d143d3230a
commit
1e56289f19
@ -249,6 +249,28 @@ pub enum Boolean<Var> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<Var: Copy> Boolean<Var> {
|
impl<Var: Copy> Boolean<Var> {
|
||||||
|
pub fn enforce_equal<E, CS>(
|
||||||
|
mut cs: CS,
|
||||||
|
a: &Self,
|
||||||
|
b: &Self
|
||||||
|
) -> Result<(), SynthesisError>
|
||||||
|
where E: Engine,
|
||||||
|
CS: ConstraintSystem<E, Variable=Var>
|
||||||
|
{
|
||||||
|
// TODO: this is just a cheap hack
|
||||||
|
let c = Self::xor(&mut cs, a, b)?;
|
||||||
|
|
||||||
|
Self::enforce_nand(&mut cs, &[c])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_value(&self) -> Option<bool> {
|
||||||
|
match self {
|
||||||
|
&Boolean::Constant(c) => Some(c),
|
||||||
|
&Boolean::Is(ref v) => v.get_value(),
|
||||||
|
&Boolean::Not(ref v) => v.get_value().map(|b| !b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Construct a boolean from a known constant
|
/// Construct a boolean from a known constant
|
||||||
pub fn constant(b: bool) -> Self {
|
pub fn constant(b: bool) -> Self {
|
||||||
Boolean::Constant(b)
|
Boolean::Constant(b)
|
||||||
@ -578,6 +600,36 @@ mod test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_enforce_equal() {
|
||||||
|
for a_bool in [false, true].iter().cloned() {
|
||||||
|
for b_bool in [false, true].iter().cloned() {
|
||||||
|
for a_neg in [false, true].iter().cloned() {
|
||||||
|
for b_neg in [false, true].iter().cloned() {
|
||||||
|
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||||
|
|
||||||
|
let mut a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_bool)).unwrap());
|
||||||
|
let mut b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_bool)).unwrap());
|
||||||
|
|
||||||
|
if a_neg {
|
||||||
|
a = a.not();
|
||||||
|
}
|
||||||
|
if b_neg {
|
||||||
|
b = b.not();
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean::enforce_equal(&mut cs, &a, &b).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
cs.is_satisfied(),
|
||||||
|
(a_bool ^ a_neg) == (b_bool ^ b_neg)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_boolean_negation() {
|
fn test_boolean_negation() {
|
||||||
let mut cs = TestConstraintSystem::<Bls12>::new();
|
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use pairing::{
|
use pairing::{
|
||||||
Engine,
|
Engine,
|
||||||
Field,
|
Field,
|
||||||
// TODO
|
PrimeField
|
||||||
// PrimeField
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use bellman::{
|
use bellman::{
|
||||||
@ -16,10 +15,15 @@ use super::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use super::num::AllocatedNum;
|
use super::num::AllocatedNum;
|
||||||
|
use super::boolean::{
|
||||||
|
Boolean
|
||||||
|
};
|
||||||
|
use super::blake2s::blake2s;
|
||||||
|
|
||||||
use ::jubjub::{
|
use ::jubjub::{
|
||||||
JubjubEngine,
|
JubjubEngine,
|
||||||
JubjubParams
|
JubjubParams,
|
||||||
|
montgomery
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct MontgomeryPoint<E: Engine, Var> {
|
pub struct MontgomeryPoint<E: Engine, Var> {
|
||||||
@ -28,6 +32,79 @@ pub struct MontgomeryPoint<E: Engine, Var> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
|
impl<E: JubjubEngine, Var: Copy> MontgomeryPoint<E, Var> {
|
||||||
|
pub fn group_hash<CS>(
|
||||||
|
mut cs: CS,
|
||||||
|
tag: &[Boolean<Var>],
|
||||||
|
params: &E::Params
|
||||||
|
) -> Result<Self, SynthesisError>
|
||||||
|
where CS: ConstraintSystem<E, Variable=Var>
|
||||||
|
{
|
||||||
|
// This code is specialized for a field of this size
|
||||||
|
assert_eq!(E::Fr::NUM_BITS, 255);
|
||||||
|
|
||||||
|
assert!(tag.len() % 8 == 0);
|
||||||
|
|
||||||
|
// TODO: first block, personalization
|
||||||
|
//
|
||||||
|
// Perform BLAKE2s hash
|
||||||
|
let h = blake2s(cs.namespace(|| "blake2s"), tag)?;
|
||||||
|
|
||||||
|
// Read the x-coordinate
|
||||||
|
let x = AllocatedNum::from_bits_strict(
|
||||||
|
cs.namespace(|| "read x coordinate"),
|
||||||
|
&h[1..]
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Allocate the y-coordinate given the first bit
|
||||||
|
// of the hash as its parity ("sign bit").
|
||||||
|
let y = AllocatedNum::alloc(
|
||||||
|
cs.namespace(|| "y-coordinate"),
|
||||||
|
|| {
|
||||||
|
let s: bool = *h[0].get_value().get()?;
|
||||||
|
let x: E::Fr = *x.get_value().get()?;
|
||||||
|
let p = montgomery::Point::<E, _>::get_for_x(x, s, params);
|
||||||
|
let p = p.get()?;
|
||||||
|
let (_, y) = p.into_xy().expect("can't be the point at infinity");
|
||||||
|
Ok(y)
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Unpack the y-coordinate
|
||||||
|
let ybits = y.into_bits_strict(cs.namespace(|| "y-coordinate unpacking"))?;
|
||||||
|
|
||||||
|
// Enforce that the y-coordinate has the right sign
|
||||||
|
Boolean::enforce_equal(
|
||||||
|
cs.namespace(|| "correct sign constraint"),
|
||||||
|
&h[0],
|
||||||
|
&ybits[E::Fr::NUM_BITS as usize - 1]
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// interpret the result as a point on the curve
|
||||||
|
let mut p = Self::interpret(
|
||||||
|
cs.namespace(|| "point interpretation"),
|
||||||
|
&x,
|
||||||
|
&y,
|
||||||
|
params
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Perform three doublings to move the point into the prime
|
||||||
|
// order subgroup.
|
||||||
|
for i in 0..3 {
|
||||||
|
// Assert the y-coordinate is nonzero (the doubling
|
||||||
|
// doesn't work for y=0).
|
||||||
|
p.y.assert_nonzero(
|
||||||
|
cs.namespace(|| format!("nonzero y-coordinate {}", i))
|
||||||
|
)?;
|
||||||
|
|
||||||
|
p = p.double(
|
||||||
|
cs.namespace(|| format!("doubling {}", i)),
|
||||||
|
params
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(p)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn interpret<CS>(
|
pub fn interpret<CS>(
|
||||||
mut cs: CS,
|
mut cs: CS,
|
||||||
x: &AllocatedNum<E, Var>,
|
x: &AllocatedNum<E, Var>,
|
||||||
@ -172,7 +249,74 @@ mod test {
|
|||||||
montgomery,
|
montgomery,
|
||||||
JubjubBls12
|
JubjubBls12
|
||||||
};
|
};
|
||||||
use super::{MontgomeryPoint, AllocatedNum};
|
use super::{MontgomeryPoint, AllocatedNum, Boolean};
|
||||||
|
use super::super::boolean::AllocatedBit;
|
||||||
|
use ::group_hash::group_hash;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_group_hash() {
|
||||||
|
let params = &JubjubBls12::new();
|
||||||
|
let rng = &mut XorShiftRng::from_seed([0x3dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
|
||||||
|
|
||||||
|
let mut num_errs = 0;
|
||||||
|
let mut num_unsatisfied = 0;
|
||||||
|
let mut num_satisfied = 0;
|
||||||
|
|
||||||
|
for _ in 0..100 {
|
||||||
|
let mut cs = TestConstraintSystem::<Bls12>::new();
|
||||||
|
|
||||||
|
let mut tag_bytes = vec![];
|
||||||
|
let mut tag = vec![];
|
||||||
|
for i in 0..10 {
|
||||||
|
let mut byte = 0;
|
||||||
|
for j in 0..8 {
|
||||||
|
byte <<= 1;
|
||||||
|
let b: bool = rng.gen();
|
||||||
|
if b {
|
||||||
|
byte |= 1;
|
||||||
|
}
|
||||||
|
tag.push(Boolean::from(
|
||||||
|
AllocatedBit::alloc(
|
||||||
|
cs.namespace(|| format!("bit {} {}", i, j)),
|
||||||
|
Some(b)
|
||||||
|
).unwrap()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
tag_bytes.push(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = MontgomeryPoint::group_hash(
|
||||||
|
cs.namespace(|| "gh"),
|
||||||
|
&tag,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = group_hash::<Bls12>(&tag_bytes, params);
|
||||||
|
|
||||||
|
if p.is_err() {
|
||||||
|
assert!(expected.is_none());
|
||||||
|
num_errs += 1;
|
||||||
|
} else {
|
||||||
|
if !cs.is_satisfied() {
|
||||||
|
assert!(expected.is_none());
|
||||||
|
num_unsatisfied += 1;
|
||||||
|
} else {
|
||||||
|
let p = p.unwrap();
|
||||||
|
let (x, y) = expected.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(p.x.get_value().unwrap(), x);
|
||||||
|
assert_eq!(p.y.get_value().unwrap(), y);
|
||||||
|
|
||||||
|
num_satisfied += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
(num_errs, num_unsatisfied, num_satisfied),
|
||||||
|
(47, 4, 49)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_interpret() {
|
fn test_interpret() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user