1
0
Fork 0
mirror of synced 2025-09-23 12:18:44 +00:00

add witness serialization, fix tests, add zkutil to test

This commit is contained in:
schaeff 2022-05-02 14:45:42 +02:00
parent a250b0b107
commit 27b65f11f6
4 changed files with 445 additions and 260 deletions

View file

@ -11,4 +11,5 @@ zokrates_field = { version = "0.5.0", path = "../zokrates_field", default-featur
byteorder = "1.4.3"
[dev-dependencies]
pretty_assertions = "1.2.1"
pretty_assertions = "1.2.1"
zkutil = "0.5.0"

View file

@ -1,260 +1,5 @@
use byteorder::{LittleEndian, WriteBytesExt};
use std::collections::HashSet;
use std::io::Result;
use std::{io::Write, ops::Add};
use zokrates_core::flat_absy::FlatVariable;
use zokrates_core::ir::{LinComb, Prog, Statement};
use zokrates_field::Field;
mod r1cs;
mod witness;
pub struct Header {
pub field_size: u32,
pub prime_size: Vec<u8>,
pub n_wires: u32,
pub n_pub_out: u32,
pub n_pub_in: u32,
pub n_prv_in: u32,
pub n_labels: u64,
pub n_constraints: u32,
}
fn write_header<W: Write>(writer: &mut W, header: Header) -> Result<()> {
writer.write_u32::<LittleEndian>(header.field_size)?;
writer.write(&header.prime_size)?;
writer.write_u32::<LittleEndian>(header.n_wires)?;
writer.write_u32::<LittleEndian>(header.n_pub_out)?;
writer.write_u32::<LittleEndian>(header.n_pub_in)?;
writer.write_u32::<LittleEndian>(header.n_prv_in)?;
writer.write_u64::<LittleEndian>(header.n_labels)?;
writer.write_u32::<LittleEndian>(header.n_constraints)?;
Ok(())
}
pub fn write_r1cs<T: Field, W: Write>(writer: &mut W, p: Prog<T>) -> Result<()> {
let modulo_byte_count = T::max_value().to_biguint().add(1u32).to_bytes_le().len() as u32;
let n_wires = p
.statements
.iter()
.fold(
HashSet::default(),
|mut acc: HashSet<FlatVariable>, s| match s {
Statement::Constraint(q, l, _) => {
acc.extend(
q.left
.0
.iter()
.chain(q.right.0.iter())
.chain(l.0.iter())
.filter_map(|(v, _)| if v.id > 0 { Some(v) } else { None }),
);
acc
}
_ => acc,
},
)
.len();
let header = Header {
field_size: modulo_byte_count,
prime_size: T::max_value().to_biguint().add(1u32).to_bytes_le(),
n_wires: n_wires as u32,
n_pub_out: p.return_count as u32,
n_pub_in: p.arguments.iter().filter(|a| !a.private).count() as u32,
n_prv_in: p.arguments.iter().filter(|a| a.private).count() as u32,
n_labels: 0,
n_constraints: p.constraint_count() as u32,
};
let shift = header.n_pub_out + header.n_pub_in;
// magic
writer.write(&[0x72, 0x31, 0x63, 0x73])?;
// version
writer.write_u32::<LittleEndian>(1)?;
// section count
writer.write_u32::<LittleEndian>(3)?;
// section type: constraints
// type
writer.write_u32::<LittleEndian>(2)?;
// size: 4 per constraint + (32 + 4) per summand
let size = p
.statements
.iter()
.map(|s| match s {
Statement::Constraint(q, l, _) => {
((q.left.0.len() + q.right.0.len() + l.0.len()) * (modulo_byte_count as usize + 4)
+ 4) as u64
}
_ => 0,
})
.sum();
writer.write_u64::<LittleEndian>(size)?;
write_constraints(writer, &p, shift)?;
// section type: header
// type
writer.write_u32::<LittleEndian>(1)?;
// size
writer.write_u64::<LittleEndian>(32 + 32)?;
// header
write_header(writer, header)?;
// section type: wire2label
// type
writer.write_u32::<LittleEndian>(3)?;
// size
writer.write_u64::<LittleEndian>(0)?;
write_table(writer, &p)?;
Ok(())
}
fn write_constraints<T: Field, W: Write>(writer: &mut W, p: &Prog<T>, shift: u32) -> Result<()> {
for s in &p.statements {
write_statement(writer, s, shift)?;
}
Ok(())
}
fn write_statement<T: Field, W: Write>(writer: &mut W, s: &Statement<T>, shift: u32) -> Result<()> {
match s {
Statement::Constraint(quad, lin, _) => {
let left = &quad.left;
write_lincomb(writer, left, shift)?;
let right = &quad.right;
write_lincomb(writer, right, shift)?;
write_lincomb(writer, lin, shift)?;
}
_ => {}
};
Ok(())
}
fn write_lincomb<T: Field, W: Write>(writer: &mut W, l: &LinComb<T>, shift: u32) -> Result<()> {
writer.write_u32::<LittleEndian>(l.0.len() as u32)?;
for (var, coeff) in &l.0 {
let shift = shift as isize;
let id = if var.id == 0 {
0
} else if var.id > 0 {
var.id + shift
} else {
assert!(-var.id <= shift);
-var.id
} as u32;
writer.write_u32::<LittleEndian>(id)?;
let mut res = vec![0u8; 32];
for (value, padded) in coeff.to_biguint().to_bytes_le().iter().zip(res.iter_mut()) {
*padded = *value;
}
writer.write(&res)?;
}
Ok(())
}
// for now we do not write any signal map
fn write_table<T: Field, W: Write>(_: &mut W, _: &Prog<T>) -> Result<()> {
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use zokrates_core::{
flat_absy::FlatVariable,
ir::{LinComb, Statement},
};
use zokrates_field::Bn128Field;
#[test]
fn empty() {
let prog: Prog<Bn128Field> = Prog::default();
let mut buf = Vec::new();
#[rustfmt::skip]
let expected: Vec<u8> = vec![
// magic
0x72, 0x31, 0x63, 0x73,
// version
0x01, 0x00, 0x00, 0x00,
// section count
0x03, 0x00, 0x00, 0x00,
// constraints section (empty)
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// header
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// modulus size in bytes
0x20, 0x00, 0x00, 0x00,
// modulus
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
// wire map (empty)
0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
write_r1cs(&mut buf, prog).unwrap();
assert_eq!(buf, expected);
}
#[test]
fn return_one() {
let prog: Prog<Bn128Field> = Prog {
arguments: vec![],
return_count: 1,
statements: vec![Statement::Constraint(
LinComb::one().into(),
FlatVariable::public(0).into(),
None,
)],
};
let mut buf = Vec::new();
#[rustfmt::skip]
let expected: Vec<u8> = vec![
0x72, 0x31, 0x63, 0x73,
0x01, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size = 1 constraint = 3 * (4 /* term_count */ + term_count * (4 + 32)) = 112
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
0x00, 0x00, 0x00, 0x00, // variable 0
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
0x00, 0x00, 0x00, 0x00, // variable 0
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
0x01, 0x00, 0x00, 0x00, // variable 1
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
// header
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x20, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
// wire map (empty)
0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
write_r1cs(&mut buf, prog).unwrap();
assert_eq!(buf, expected);
}
}
pub use r1cs::write_r1cs;
pub use witness::write_witness;

294
zokrates_circom/src/r1cs.rs Normal file
View file

@ -0,0 +1,294 @@
use byteorder::{LittleEndian, WriteBytesExt};
use std::collections::BTreeSet;
use std::io::Result;
use std::{io::Write, ops::Add};
use zokrates_core::flat_absy::FlatVariable;
use zokrates_core::ir::{LinComb, Prog, Statement};
use zokrates_field::Field;
struct Header {
pub field_size: u32,
pub prime_size: Vec<u8>,
pub n_wires: u32,
pub n_pub_out: u32,
pub n_pub_in: u32,
pub n_prv_in: u32,
pub n_labels: u64,
pub n_constraints: u32,
}
fn write_header<W: Write>(writer: &mut W, header: Header) -> Result<()> {
writer.write_u32::<LittleEndian>(header.field_size)?;
writer.write(&header.prime_size)?;
writer.write_u32::<LittleEndian>(header.n_wires)?;
writer.write_u32::<LittleEndian>(header.n_pub_out)?;
writer.write_u32::<LittleEndian>(header.n_pub_in)?;
writer.write_u32::<LittleEndian>(header.n_prv_in)?;
writer.write_u64::<LittleEndian>(header.n_labels)?;
writer.write_u32::<LittleEndian>(header.n_constraints)?;
Ok(())
}
pub fn write_r1cs<T: Field, W: Write>(writer: &mut W, p: Prog<T>) -> Result<()> {
let modulo_byte_count = T::max_value().to_biguint().add(1u32).to_bytes_le().len() as u32;
let n_pub_out = p.return_count as u32;
let n_pub_in = p.arguments.iter().filter(|a| !a.private).count() as u32;
let shift = n_pub_out + n_pub_in;
let wires = p.statements.iter().fold(
vec![0u32].into_iter().collect::<BTreeSet<_>>(),
|mut acc: BTreeSet<u32>, s| match s {
Statement::Constraint(q, l, _) => {
acc.extend(
q.left
.0
.iter()
.chain(q.right.0.iter())
.chain(l.0.iter())
.map(|(v, _)| shift_variable(v, shift)),
);
acc
}
_ => acc,
},
);
let n_wires = wires.len();
let header = Header {
field_size: modulo_byte_count,
prime_size: T::max_value().to_biguint().add(1u32).to_bytes_le(),
n_wires: n_wires as u32,
n_pub_out,
n_pub_in,
n_prv_in: p.arguments.iter().filter(|a| a.private).count() as u32,
n_labels: n_wires as u64,
n_constraints: p.constraint_count() as u32,
};
let shift = header.n_pub_out + header.n_pub_in;
// magic
writer.write(&[0x72, 0x31, 0x63, 0x73])?;
// version
writer.write_u32::<LittleEndian>(1)?;
// section count
writer.write_u32::<LittleEndian>(3)?;
// section type: constraints
// type
writer.write_u32::<LittleEndian>(2)?;
// size: 4 per lc + (32 + 4) per summand
let size = p
.statements
.iter()
.map(|s| match s {
Statement::Constraint(q, l, _) => {
(3 * 4 // for each lc, 4 bytes for its size
+ (q.left.0.len() + q.right.0.len() + l.0.len()) // for each summand
* (modulo_byte_count as usize + 4)) // 4 bytes for the signal, `modulo_byte_count` bytes for the coefficient
as u64
}
_ => 0,
})
.sum();
writer.write_u64::<LittleEndian>(size)?;
write_constraints(writer, &p, shift)?;
// section type: header
// type
writer.write_u32::<LittleEndian>(1)?;
// size
writer.write_u64::<LittleEndian>(32 + 32)?;
// header
write_header(writer, header)?;
// section type: wire2label
// type
writer.write_u32::<LittleEndian>(3)?;
// size
writer.write_u64::<LittleEndian>(n_wires as u64 * 8)?;
write_table(writer, &wires)?;
Ok(())
}
fn write_constraints<T: Field, W: Write>(writer: &mut W, p: &Prog<T>, shift: u32) -> Result<()> {
for s in &p.statements {
write_statement(writer, s, shift)?;
}
Ok(())
}
fn write_statement<T: Field, W: Write>(writer: &mut W, s: &Statement<T>, shift: u32) -> Result<()> {
match s {
Statement::Constraint(quad, lin, _) => {
let left = &quad.left;
write_lincomb(writer, left, shift)?;
let right = &quad.right;
write_lincomb(writer, right, shift)?;
write_lincomb(writer, lin, shift)?;
}
_ => {}
};
Ok(())
}
fn shift_variable(var: &FlatVariable, shift: u32) -> u32 {
let shift = shift as isize;
let id = if var.id == 0 {
0
} else if var.id > 0 {
var.id + shift
} else {
assert!(-var.id <= shift);
-var.id
};
id as u32
}
fn write_lincomb<T: Field, W: Write>(writer: &mut W, l: &LinComb<T>, shift: u32) -> Result<()> {
writer.write_u32::<LittleEndian>(l.0.len() as u32)?;
for (var, coeff) in &l.0 {
let id = shift_variable(var, shift);
writer.write_u32::<LittleEndian>(id)?;
let mut res = vec![0u8; 32];
for (value, padded) in coeff.to_biguint().to_bytes_le().iter().zip(res.iter_mut()) {
*padded = *value;
}
writer.write(&res)?;
}
Ok(())
}
// for now we do not write any signal map
fn write_table<W: Write>(w: &mut W, variables: &BTreeSet<u32>) -> Result<()> {
for v in variables {
w.write_u64::<LittleEndian>(*v as u64)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use std::io::Cursor;
use super::*;
use pretty_assertions::assert_eq;
use zkutil::r1cs_reader;
use zokrates_core::{
flat_absy::FlatVariable,
ir::{LinComb, Statement},
};
use zokrates_field::Bn128Field;
#[test]
fn empty() {
let prog: Prog<Bn128Field> = Prog::default();
let mut buf = Vec::new();
#[rustfmt::skip]
let expected: Vec<u8> = vec![
// magic
0x72, 0x31, 0x63, 0x73,
// version
0x01, 0x00, 0x00, 0x00,
// section count
0x03, 0x00, 0x00, 0x00,
// constraints section (empty)
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// header
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// modulus size in bytes
0x20, 0x00, 0x00, 0x00,
// modulus
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
// n wires
0x01, 0x00, 0x00, 0x00,
// n pub outputs
0x00, 0x00, 0x00, 0x00,
// n pub inputs
0x00, 0x00, 0x00, 0x00,
// n priv
0x00, 0x00, 0x00, 0x00,
// n labels
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// n constraints
0x00, 0x00, 0x00, 0x00,
// wire map (variable one?)
0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
write_r1cs(&mut buf, prog).unwrap();
assert_eq!(buf, expected);
let c = Cursor::new(buf);
assert!(r1cs_reader::read(c).is_ok());
}
#[test]
fn return_one() {
let prog: Prog<Bn128Field> = Prog {
arguments: vec![],
return_count: 1,
statements: vec![Statement::Constraint(
LinComb::one().into(),
FlatVariable::public(0).into(),
None,
)],
};
let mut buf = Vec::new();
#[rustfmt::skip]
let expected: Vec<u8> = vec![
0x72, 0x31, 0x63, 0x73,
0x01, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // size = 1 constraint = sum(4 /* write term_count_i */ + term_count_i * (4 + 32)) = 120
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
0x00, 0x00, 0x00, 0x00, // variable 0
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
0x00, 0x00, 0x00, 0x00, // variable 0
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
0x01, 0x00, 0x00, 0x00, // 1 element in this lc
0x01, 0x00, 0x00, 0x00, // variable 1
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // coeff 1
// header
0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// modulo size
0x20, 0x00, 0x00, 0x00,
// modulo
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
0x02, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00,
// wire map (one, pub0)
0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
write_r1cs(&mut buf, prog).unwrap();
assert_eq!(buf, expected);
let c = Cursor::new(buf);
assert!(r1cs_reader::read(c).is_ok());
}
}

View file

@ -0,0 +1,145 @@
use std::{
io::{Result, Write},
ops::Add,
};
use byteorder::{LittleEndian, WriteBytesExt};
use zokrates_core::ir::Witness;
use zokrates_field::Field;
pub struct Header {
pub field_size: u32,
pub prime_size: Vec<u8>,
pub witness_size: u32,
}
fn write_header<W: Write>(writer: &mut W, header: Header) -> Result<()> {
writer.write_u32::<LittleEndian>(header.field_size)?;
writer.write(&header.prime_size)?;
writer.write_u32::<LittleEndian>(header.witness_size)?;
Ok(())
}
pub fn write_witness<T: Field, W: Write>(writer: &mut W, w: Witness<T>) -> Result<()> {
let modulo_byte_count = T::max_value().to_biguint().add(1u32).to_bytes_le().len() as u32;
let witness_size = w.0.len() as u32;
let header = Header {
field_size: modulo_byte_count,
prime_size: T::max_value().to_biguint().add(1u32).to_bytes_le(),
witness_size,
};
// magic "wtns"
writer.write(&[0x77, 0x74, 0x6e, 0x73])?;
// version
writer.write_u32::<LittleEndian>(2)?;
// section count
writer.write_u32::<LittleEndian>(2)?;
// section type: header
// type
writer.write_u32::<LittleEndian>(1)?;
// size
writer.write_u64::<LittleEndian>(8 + modulo_byte_count as u64)?;
// header
write_header(writer, header)?;
// section type: witness
// type
writer.write_u32::<LittleEndian>(2)?;
// size: `modulo_byte_count` per witness value
let size = witness_size as u64 * modulo_byte_count as u64;
writer.write_u64::<LittleEndian>(size)?;
write_witness_values(writer, &w)?;
Ok(())
}
fn write_witness_values<T: Field, W: Write>(writer: &mut W, w: &Witness<T>) -> Result<()> {
let modulo_byte_count = T::max_value().to_biguint().add(1u32).to_bytes_le().len();
for (_, val) in w.0.iter() {
let mut res = vec![0u8; modulo_byte_count];
for (value, padded) in val.to_biguint().to_bytes_le().iter().zip(res.iter_mut()) {
*padded = *value;
}
writer.write(&res)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
use zokrates_core::flat_absy::FlatVariable;
use zokrates_field::Bn128Field;
#[test]
fn empty() {
let w: Witness<Bn128Field> = Witness::default();
let mut buf = Vec::new();
#[rustfmt::skip]
let expected: Vec<u8> = vec![
// magic
0x74, 0x77, 0x73, 0x6e,
// version
0x02, 0x00, 0x00, 0x00,
// section count
0x02, 0x00, 0x00, 0x00,
// header
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// modulus size in bytes
0x20, 0x00, 0x00, 0x00,
// modulus
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
// witness size
0x00, 0x00, 0x00, 0x00,
// witness section (empty)
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
write_witness(&mut buf, w).unwrap();
assert_eq!(buf, expected);
}
#[test]
fn one_value() {
let mut w: Witness<Bn128Field> = Witness::default();
w.0.insert(FlatVariable::public(0), 1.into());
let mut buf = Vec::new();
#[rustfmt::skip]
let expected: Vec<u8> = vec![
// magic
0x74, 0x77, 0x73, 0x6e,
// version
0x02, 0x00, 0x00, 0x00,
// section count
0x02, 0x00, 0x00, 0x00,
// header
0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// modulus size in bytes
0x20, 0x00, 0x00, 0x00,
// modulus
0x01, 0x00, 0x00, 0xf0, 0x93, 0xf5, 0xe1, 0x43, 0x91, 0x70, 0xb9, 0x79, 0x48, 0xe8, 0x33, 0x28, 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30,
// witness size
0x01, 0x00, 0x00, 0x00,
// witness section
0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// values
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
];
write_witness(&mut buf, w).unwrap();
assert_eq!(buf, expected);
}
}