use crate::algebra::blade_new::BladeKey;
use crate::algebra::mv::Mv;
use crate::algebra::signature::Signature;
use crate::governance::construction::Construction;
use crate::governance::expr::Expr;
use crate::governance::field::{FieldOp, ProbeSpec};
use crate::governance::geoit::GeoitSnapshot;
use crate::governance::geom_class::GeomClass;
use crate::governance::governance::Governance;
use crate::governance::phase::Phase;
use crate::governance::poly::Poly;
use crate::governance::predicate::Predicate;
use crate::governance::profile::GeneratorProfile;
use crate::governance::reading::{ExtractionMap, ReadingRules};
use crate::governance::rule::ProofTerm;
use crate::scalar::bigint::{BigInt, BigUint};
use crate::scalar::bigrat::BigRat;
use crate::scalar::coeff::Coeff;
use crate::scalar::promote::Scalar;
use crate::scalar::radical::{RadicalElement, RadicalLayer, RadicalTower};
use crate::scalar::rat::Rat;
use std::sync::Arc;
const MAGIC: &[u8; 5] = b"GEOIT";
const VERSION: u8 = 2;
#[derive(Clone, Debug)]
pub enum CodecError {
BadMagic,
UnsupportedVersion(u8),
UnexpectedEof,
InvalidTag { context: &'static str, tag: u8 },
InvalidData(String),
}
impl std::fmt::Display for CodecError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CodecError::BadMagic => write!(f, "bad magic (not a GEOIT file)"),
CodecError::UnsupportedVersion(v) => write!(f, "unsupported version {}", v),
CodecError::UnexpectedEof => write!(f, "unexpected end of data"),
CodecError::InvalidTag { context, tag } => {
write!(f, "invalid tag {} in {}", tag, context)
}
CodecError::InvalidData(msg) => write!(f, "invalid data: {}", msg),
}
}
}
pub fn encode(snapshot: &GeoitSnapshot) -> Vec<u8> {
let mut buf = Vec::with_capacity(1024);
buf.extend_from_slice(MAGIC);
buf.push(VERSION);
enc_snapshot(&mut buf, snapshot);
buf
}
pub fn decode(data: &[u8]) -> Result<GeoitSnapshot, CodecError> {
let mut cur = Cur::new(data);
let magic = cur.bytes(5)?;
if magic != MAGIC {
return Err(CodecError::BadMagic);
}
let ver = cur.u8()?;
if ver != VERSION {
return Err(CodecError::UnsupportedVersion(ver));
}
dec_snapshot(&mut cur)
}
pub fn encode_governance(gov: &Governance) -> Vec<u8> {
let mut buf = Vec::with_capacity(512);
buf.extend_from_slice(MAGIC);
buf.push(VERSION);
enc_gov(&mut buf, gov);
buf
}
pub fn decode_governance(data: &[u8]) -> Result<Governance, CodecError> {
let mut cur = Cur::new(data);
let magic = cur.bytes(5)?;
if magic != MAGIC {
return Err(CodecError::BadMagic);
}
let ver = cur.u8()?;
if ver != VERSION {
return Err(CodecError::UnsupportedVersion(ver));
}
dec_gov(&mut cur)
}
pub fn encode_mv(mv: &Mv) -> Vec<u8> {
let mut buf = Vec::with_capacity(256);
buf.extend_from_slice(MAGIC);
buf.push(VERSION);
enc_mv(&mut buf, mv);
buf
}
pub fn decode_mv(data: &[u8]) -> Result<Mv, CodecError> {
let mut cur = Cur::new(data);
let magic = cur.bytes(5)?;
if magic != MAGIC {
return Err(CodecError::BadMagic);
}
let ver = cur.u8()?;
if ver != VERSION {
return Err(CodecError::UnsupportedVersion(ver));
}
dec_mv(&mut cur)
}
struct Cur<'a> {
data: &'a [u8],
pos: usize,
}
impl<'a> Cur<'a> {
fn new(data: &'a [u8]) -> Self {
Cur { data, pos: 0 }
}
fn u8(&mut self) -> Result<u8, CodecError> {
if self.pos >= self.data.len() {
return Err(CodecError::UnexpectedEof);
}
let v = self.data[self.pos];
self.pos += 1;
Ok(v)
}
fn bytes(&mut self, n: usize) -> Result<&'a [u8], CodecError> {
if self.pos + n > self.data.len() {
return Err(CodecError::UnexpectedEof);
}
let s = &self.data[self.pos..self.pos + n];
self.pos += n;
Ok(s)
}
fn u16le(&mut self) -> Result<u16, CodecError> {
let b = self.bytes(2)?;
Ok(u16::from_le_bytes([b[0], b[1]]))
}
fn u32le(&mut self) -> Result<u32, CodecError> {
let b = self.bytes(4)?;
Ok(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
}
fn u64le(&mut self) -> Result<u64, CodecError> {
let b = self.bytes(8)?;
Ok(u64::from_le_bytes(b.try_into().unwrap()))
}
fn i128le(&mut self) -> Result<i128, CodecError> {
let b = self.bytes(16)?;
Ok(i128::from_le_bytes(b.try_into().unwrap()))
}
fn u128le(&mut self) -> Result<u128, CodecError> {
let b = self.bytes(16)?;
Ok(u128::from_le_bytes(b.try_into().unwrap()))
}
fn leb128(&mut self) -> Result<usize, CodecError> {
let mut r: usize = 0;
let mut s = 0;
loop {
let b = self.u8()?;
r |= ((b & 0x7F) as usize) << s;
if b & 0x80 == 0 {
break;
}
s += 7;
if s >= 64 {
return Err(CodecError::InvalidData("LEB128 overflow".into()));
}
}
Ok(r)
}
fn bool(&mut self) -> Result<bool, CodecError> {
Ok(self.u8()? != 0)
}
}
fn wu8(b: &mut Vec<u8>, v: u8) {
b.push(v);
}
fn wu16(b: &mut Vec<u8>, v: u16) {
b.extend_from_slice(&v.to_le_bytes());
}
fn wu32(b: &mut Vec<u8>, v: u32) {
b.extend_from_slice(&v.to_le_bytes());
}
fn wu64(b: &mut Vec<u8>, v: u64) {
b.extend_from_slice(&v.to_le_bytes());
}
fn wi128(b: &mut Vec<u8>, v: i128) {
b.extend_from_slice(&v.to_le_bytes());
}
fn wu128(b: &mut Vec<u8>, v: u128) {
b.extend_from_slice(&v.to_le_bytes());
}
fn wbool(b: &mut Vec<u8>, v: bool) {
b.push(u8::from(v));
}
fn wleb(b: &mut Vec<u8>, mut v: usize) {
loop {
let mut byte = (v & 0x7F) as u8;
v >>= 7;
if v != 0 {
byte |= 0x80;
}
b.push(byte);
if v == 0 {
break;
}
}
}
fn enc_rat(b: &mut Vec<u8>, r: &Rat) {
wi128(b, r.num());
wu128(b, r.den());
}
fn dec_rat(c: &mut Cur) -> Result<Rat, CodecError> {
let num = c.i128le()?;
let den = c.u128le()?;
if den == 0 {
return Err(CodecError::InvalidData("Rat den=0".into()));
}
Ok(Rat::new(num, den as i128))
}
fn enc_biguint(b: &mut Vec<u8>, v: &BigUint) {
let limbs = v.limbs();
wleb(b, limbs.len());
for &l in limbs {
wu64(b, l);
}
}
fn dec_biguint(c: &mut Cur) -> Result<BigUint, CodecError> {
let n = c.leb128()?;
let mut limbs = Vec::with_capacity(n);
for _ in 0..n {
limbs.push(c.u64le()?);
}
Ok(BigUint::from_limbs(limbs))
}
fn enc_bigint(b: &mut Vec<u8>, v: &BigInt) {
wbool(b, v.is_negative());
enc_biguint(b, v.magnitude());
}
fn dec_bigint(c: &mut Cur) -> Result<BigInt, CodecError> {
let neg = c.bool()?;
let mag = dec_biguint(c)?;
Ok(BigInt::from_sign_mag(neg, mag))
}
fn enc_bigrat(b: &mut Vec<u8>, v: &BigRat) {
enc_bigint(b, v.numerator());
enc_biguint(b, v.denominator());
}
fn dec_bigrat(c: &mut Cur) -> Result<BigRat, CodecError> {
let num = dec_bigint(c)?;
let den = dec_biguint(c)?;
let den_int = BigInt::from_sign_mag(false, den);
Ok(BigRat::new(num, den_int))
}
fn enc_radical_layer(b: &mut Vec<u8>, l: &RadicalLayer) {
wu32(b, l.degree);
wleb(b, l.min_poly.len());
for r in &l.min_poly {
enc_rat(b, r);
}
}
fn dec_radical_layer(c: &mut Cur) -> Result<RadicalLayer, CodecError> {
let degree = c.u32le()?;
let n = c.leb128()?;
let mut mp = Vec::with_capacity(n);
for _ in 0..n {
mp.push(dec_rat(c)?);
}
Ok(RadicalLayer {
degree,
min_poly: mp,
})
}
fn enc_radical(b: &mut Vec<u8>, r: &RadicalElement) {
let t = r.tower();
wleb(b, t.layers.len());
for l in &t.layers {
enc_radical_layer(b, l);
}
wleb(b, r.coeffs.len());
for c in &r.coeffs {
enc_coeff(b, c);
}
}
fn dec_radical(c: &mut Cur) -> Result<RadicalElement, CodecError> {
let nl = c.leb128()?;
let mut layers = Vec::with_capacity(nl);
for _ in 0..nl {
layers.push(dec_radical_layer(c)?);
}
let td: usize = if layers.is_empty() {
1
} else {
layers.iter().map(|l| l.degree as usize).product()
};
let tower = Arc::new(RadicalTower {
layers,
total_degree: td,
});
let nc = c.leb128()?;
let mut coeffs = Vec::with_capacity(nc);
for _ in 0..nc {
coeffs.push(dec_coeff(c)?);
}
Ok(RadicalElement::new(coeffs, tower))
}
fn enc_coeff(b: &mut Vec<u8>, c: &Coeff) {
match c {
Coeff::Rat(r) => {
b.push(0);
enc_rat(b, r);
}
Coeff::Big(br) => {
b.push(1);
enc_bigrat(b, br);
}
}
}
fn dec_coeff(c: &mut Cur) -> Result<Coeff, CodecError> {
let tag = c.u8()?;
match tag {
0 => Ok(Coeff::Rat(dec_rat(c)?)),
1 => Ok(Coeff::from_bigrat(dec_bigrat(c)?)),
_ => Err(CodecError::InvalidTag {
context: "Coeff",
tag,
}),
}
}
fn enc_scalar(b: &mut Vec<u8>, s: &Scalar) {
match s {
Scalar::Rat(r) => {
wu8(b, 0);
enc_rat(b, r);
}
Scalar::Big(v) => {
wu8(b, 1);
enc_bigrat(b, v);
}
Scalar::Radical(r) => {
wu8(b, 2);
enc_radical(b, r);
}
}
}
fn dec_scalar(c: &mut Cur) -> Result<Scalar, CodecError> {
match c.u8()? {
0 => Ok(Scalar::Rat(dec_rat(c)?)),
1 => Ok(Scalar::Big(dec_bigrat(c)?)),
2 => Ok(Scalar::Radical(dec_radical(c)?)),
t => Err(CodecError::InvalidTag {
context: "Scalar",
tag: t,
}),
}
}
fn enc_sig(b: &mut Vec<u8>, s: &Signature) {
wu8(b, s.i);
wu8(b, s.d);
wu8(b, s.h);
}
fn dec_sig(c: &mut Cur) -> Result<Signature, CodecError> {
let i = c.u8()?;
let d = c.u8()?;
let h = c.u8()?;
Signature::new(i, d, h).map_err(|e| CodecError::InvalidData(format!("{}", e)))
}
fn enc_bladekey(b: &mut Vec<u8>, bk: &BladeKey) {
wu8(b, bk.grade());
for &idx in bk.indices() {
wu16(b, idx);
}
}
fn dec_bladekey(c: &mut Cur) -> Result<BladeKey, CodecError> {
let g = c.u8()?;
if g == 0 {
return Ok(BladeKey::SCALAR);
}
let mut idx = Vec::with_capacity(g as usize);
for _ in 0..g {
idx.push(c.u16le()?);
}
Ok(BladeKey::from_sorted(&idx))
}
fn enc_mv(b: &mut Vec<u8>, mv: &Mv) {
wleb(b, mv.terms.len());
for (bk, coeff) in &mv.terms {
enc_bladekey(b, bk);
enc_scalar(b, coeff);
}
}
fn dec_mv(c: &mut Cur) -> Result<Mv, CodecError> {
let n = c.leb128()?;
let mut terms = Vec::with_capacity(n);
for _ in 0..n {
terms.push((dec_bladekey(c)?, dec_scalar(c)?));
}
Ok(Mv { terms })
}
fn enc_poly(b: &mut Vec<u8>, p: &Poly) {
wleb(b, p.num_vars);
let terms: Vec<_> = p.terms.iter().collect();
wleb(b, terms.len());
for (exp, &coeff) in &terms {
for &e in exp.iter() {
wu8(b, e);
}
enc_rat(b, &coeff);
}
}
fn dec_poly(c: &mut Cur) -> Result<Poly, CodecError> {
let nv = c.leb128()?;
let nt = c.leb128()?;
let mut p = Poly::zero(nv);
for _ in 0..nt {
let mut exp = vec![0u8; nv];
for e in exp.iter_mut() {
*e = c.u8()?;
}
let coeff = dec_rat(c)?;
p.add_term(exp, coeff);
}
Ok(p)
}
fn enc_phase(b: &mut Vec<u8>, p: &Phase) {
wu8(
b,
match p {
Phase::Deliberation => 0,
Phase::Evaluation => 1,
Phase::Commitment => 2,
},
);
}
fn dec_phase(c: &mut Cur) -> Result<Phase, CodecError> {
match c.u8()? {
0 => Ok(Phase::Deliberation),
1 => Ok(Phase::Evaluation),
2 => Ok(Phase::Commitment),
t => Err(CodecError::InvalidTag {
context: "Phase",
tag: t,
}),
}
}
fn enc_fieldop(b: &mut Vec<u8>, op: &FieldOp) {
match op {
FieldOp::ScalarProduct => wu8(b, 0),
FieldOp::OuterProduct => wu8(b, 1),
FieldOp::LeftContraction => wu8(b, 2),
FieldOp::GradeProduct(k) => {
wu8(b, 3);
wu8(b, *k);
}
FieldOp::InnerProduct => wu8(b, 4),
FieldOp::GeometricProduct => wu8(b, 5),
}
}
fn dec_fieldop(c: &mut Cur) -> Result<FieldOp, CodecError> {
match c.u8()? {
0 => Ok(FieldOp::ScalarProduct),
1 => Ok(FieldOp::OuterProduct),
2 => Ok(FieldOp::LeftContraction),
3 => Ok(FieldOp::GradeProduct(c.u8()?)),
4 => Ok(FieldOp::InnerProduct),
5 => Ok(FieldOp::GeometricProduct),
t => Err(CodecError::InvalidTag {
context: "FieldOp",
tag: t,
}),
}
}
fn enc_probe(b: &mut Vec<u8>, ps: &ProbeSpec) {
wleb(b, ps.construction_index);
wleb(b, ps.arity);
}
fn dec_probe(c: &mut Cur) -> Result<ProbeSpec, CodecError> {
Ok(ProbeSpec {
construction_index: c.leb128()?,
arity: c.leb128()?,
})
}
fn enc_geomclass(b: &mut Vec<u8>, gc: &GeomClass) {
wu64(b, gc.grade_mask);
wleb(b, gc.equations.len());
for p in &gc.equations {
enc_poly(b, p);
}
wleb(b, gc.inequalities.len());
for p in &gc.inequalities {
enc_poly(b, p);
}
enc_fieldop(b, &gc.field_op);
}
fn dec_geomclass(c: &mut Cur) -> Result<GeomClass, CodecError> {
let gm = c.u64le()?;
let ne = c.leb128()?;
let mut eq = Vec::with_capacity(ne);
for _ in 0..ne {
eq.push(dec_poly(c)?);
}
let ni = c.leb128()?;
let mut iq = Vec::with_capacity(ni);
for _ in 0..ni {
iq.push(dec_poly(c)?);
}
let fo = dec_fieldop(c)?;
Ok(GeomClass {
grade_mask: gm,
equations: eq,
inequalities: iq,
field_op: fo,
expected_profile: None,
})
}
fn enc_expr(b: &mut Vec<u8>, e: &Expr) {
match e {
Expr::Param(i) => {
wu8(b, 0);
wleb(b, *i);
}
Expr::Generator(k) => {
wu8(b, 1);
wu8(b, *k);
}
Expr::DerivedGen(i) => {
wu8(b, 2);
wleb(b, *i);
}
Expr::Literal(s) => {
wu8(b, 3);
enc_scalar(b, s);
}
Expr::Add(a, c) => {
wu8(b, 4);
enc_expr(b, a);
enc_expr(b, c);
}
Expr::Mul(a, c) => {
wu8(b, 5);
enc_expr(b, a);
enc_expr(b, c);
}
Expr::Neg(a) => {
wu8(b, 6);
enc_expr(b, a);
}
Expr::Pow(a, n) => {
wu8(b, 7);
enc_expr(b, a);
wu32(b, *n);
}
Expr::Construct(i, args) => {
wu8(b, 8);
wleb(b, *i);
wleb(b, args.len());
for a in args {
enc_expr(b, a);
}
}
Expr::Outer(a, c) => {
wu8(b, 9);
enc_expr(b, a);
enc_expr(b, c);
}
Expr::Inner(a, c) => {
wu8(b, 10);
enc_expr(b, a);
enc_expr(b, c);
}
Expr::Reverse(a) => {
wu8(b, 11);
enc_expr(b, a);
}
Expr::Dual(a) => {
wu8(b, 12);
enc_expr(b, a);
}
Expr::Sandwich(a, c) => {
wu8(b, 13);
enc_expr(b, a);
enc_expr(b, c);
}
Expr::ValueRef(i) => {
wu8(b, 14);
wleb(b, *i);
}
Expr::GradeProject(a, k) => {
wu8(b, 15);
enc_expr(b, a);
wu8(b, *k);
}
Expr::LeftContract(a, c) => {
wu8(b, 16);
enc_expr(b, a);
enc_expr(b, c);
}
Expr::ScalarProduct(a, c) => {
wu8(b, 17);
enc_expr(b, a);
enc_expr(b, c);
}
Expr::Read(a, i) => {
wu8(b, 18);
enc_expr(b, a);
wleb(b, *i);
}
Expr::WithGov(i, a) => {
wu8(b, 19);
wleb(b, *i);
enc_expr(b, a);
}
Expr::Embed(a, i) => {
wu8(b, 20);
enc_expr(b, a);
wleb(b, *i);
}
Expr::Morph(a, i) => {
wu8(b, 21);
enc_expr(b, a);
wleb(b, *i);
}
Expr::Probe => {
wu8(b, 22);
}
Expr::Object => {
wu8(b, 23);
}
}
}
fn dec_expr(c: &mut Cur) -> Result<Expr, CodecError> {
match c.u8()? {
0 => Ok(Expr::Param(c.leb128()?)),
1 => Ok(Expr::Generator(c.u8()?)),
2 => Ok(Expr::DerivedGen(c.leb128()?)),
3 => Ok(Expr::Literal(dec_scalar(c)?)),
4 => Ok(Expr::Add(Box::new(dec_expr(c)?), Box::new(dec_expr(c)?))),
5 => Ok(Expr::Mul(Box::new(dec_expr(c)?), Box::new(dec_expr(c)?))),
6 => Ok(Expr::Neg(Box::new(dec_expr(c)?))),
7 => {
let a = dec_expr(c)?;
let n = c.u32le()?;
Ok(Expr::Pow(Box::new(a), n))
}
8 => {
let i = c.leb128()?;
let n = c.leb128()?;
let mut v = Vec::with_capacity(n);
for _ in 0..n {
v.push(Box::new(dec_expr(c)?));
}
Ok(Expr::Construct(i, v))
}
9 => Ok(Expr::Outer(Box::new(dec_expr(c)?), Box::new(dec_expr(c)?))),
10 => Ok(Expr::Inner(Box::new(dec_expr(c)?), Box::new(dec_expr(c)?))),
11 => Ok(Expr::Reverse(Box::new(dec_expr(c)?))),
12 => Ok(Expr::Dual(Box::new(dec_expr(c)?))),
13 => Ok(Expr::Sandwich(
Box::new(dec_expr(c)?),
Box::new(dec_expr(c)?),
)),
14 => Ok(Expr::ValueRef(c.leb128()?)),
15 => {
let a = dec_expr(c)?;
let k = c.u8()?;
Ok(Expr::GradeProject(Box::new(a), k))
}
16 => Ok(Expr::LeftContract(
Box::new(dec_expr(c)?),
Box::new(dec_expr(c)?),
)),
17 => Ok(Expr::ScalarProduct(
Box::new(dec_expr(c)?),
Box::new(dec_expr(c)?),
)),
18 => {
let a = dec_expr(c)?;
let i = c.leb128()?;
Ok(Expr::Read(Box::new(a), i))
}
19 => {
let i = c.leb128()?;
let a = dec_expr(c)?;
Ok(Expr::WithGov(i, Box::new(a)))
}
20 => {
let a = dec_expr(c)?;
let i = c.leb128()?;
Ok(Expr::Embed(Box::new(a), i))
}
21 => {
let a = dec_expr(c)?;
let i = c.leb128()?;
Ok(Expr::Morph(Box::new(a), i))
}
22 => Ok(Expr::Probe),
23 => Ok(Expr::Object),
t => Err(CodecError::InvalidTag {
context: "Expr",
tag: t,
}),
}
}
fn enc_construction(b: &mut Vec<u8>, c: &Construction) {
wleb(b, c.class_index);
wleb(b, c.arity);
enc_expr(b, &c.body);
}
fn dec_construction(c: &mut Cur) -> Result<Construction, CodecError> {
Ok(Construction {
class_index: c.leb128()?,
arity: c.leb128()?,
body: dec_expr(c)?,
})
}
fn enc_extmap(b: &mut Vec<u8>, em: &ExtractionMap) {
match em {
ExtractionMap::Coefficient(m) => {
wu8(b, 0);
wu64(b, *m);
}
ExtractionMap::Linear(terms) => {
wu8(b, 1);
wleb(b, terms.len());
for &(m, ref s) in terms {
wu64(b, m);
enc_scalar(b, s);
}
}
ExtractionMap::Rational {
numerator,
denominator,
} => {
wu8(b, 2);
wleb(b, numerator.len());
for &(m, ref s) in numerator {
wu64(b, m);
enc_scalar(b, s);
}
wleb(b, denominator.len());
for &(m, ref s) in denominator {
wu64(b, m);
enc_scalar(b, s);
}
}
}
}
fn dec_extmap(c: &mut Cur) -> Result<ExtractionMap, CodecError> {
match c.u8()? {
0 => Ok(ExtractionMap::Coefficient(c.u64le()?)),
1 => {
let n = c.leb128()?;
let mut v = Vec::with_capacity(n);
for _ in 0..n {
v.push((c.u64le()?, dec_scalar(c)?));
}
Ok(ExtractionMap::Linear(v))
}
2 => {
let nn = c.leb128()?;
let mut num = Vec::with_capacity(nn);
for _ in 0..nn {
num.push((c.u64le()?, dec_scalar(c)?));
}
let nd = c.leb128()?;
let mut den = Vec::with_capacity(nd);
for _ in 0..nd {
den.push((c.u64le()?, dec_scalar(c)?));
}
Ok(ExtractionMap::Rational {
numerator: num,
denominator: den,
})
}
t => Err(CodecError::InvalidTag {
context: "ExtractionMap",
tag: t,
}),
}
}
fn enc_readings(b: &mut Vec<u8>, rr: &ReadingRules) {
wleb(b, rr.extractions.len());
for em in &rr.extractions {
enc_extmap(b, em);
}
}
fn dec_readings(c: &mut Cur) -> Result<ReadingRules, CodecError> {
let n = c.leb128()?;
let mut v = Vec::with_capacity(n);
for _ in 0..n {
v.push(dec_extmap(c)?);
}
Ok(ReadingRules { extractions: v })
}
fn enc_predicate(b: &mut Vec<u8>, p: &Predicate) {
wleb(b, p.class_index);
wleb(b, p.equations_satisfied.len());
for &v in &p.equations_satisfied {
wbool(b, v);
}
wleb(b, p.inequalities_satisfied.len());
for &v in &p.inequalities_satisfied {
wbool(b, v);
}
wbool(b, p.overflow_promoted);
}
fn dec_predicate(c: &mut Cur) -> Result<Predicate, CodecError> {
let ci = c.leb128()?;
let ne = c.leb128()?;
let mut es = Vec::with_capacity(ne);
for _ in 0..ne {
es.push(c.bool()?);
}
let ni = c.leb128()?;
let mut is = Vec::with_capacity(ni);
for _ in 0..ni {
is.push(c.bool()?);
}
let ov = c.bool()?;
Ok(Predicate::new(ci, &[], &[], es, is, ov))
}
fn enc_gov(b: &mut Vec<u8>, g: &Governance) {
enc_sig(b, &g.sig);
wleb(b, g.derived_gens.len());
for dg in &g.derived_gens {
enc_mv(b, dg);
}
wleb(b, g.geom_classes.len());
for gc in &g.geom_classes {
enc_geomclass(b, gc);
}
wleb(b, g.constructions.len());
for c in &g.constructions {
enc_construction(b, c);
}
match &g.probe {
None => wu8(b, 0),
Some(ps) => {
wu8(b, 1);
enc_probe(b, ps);
}
}
}
fn dec_gov(c: &mut Cur) -> Result<Governance, CodecError> {
let sig = dec_sig(c)?;
let nd = c.leb128()?;
let mut dg = Vec::with_capacity(nd);
for _ in 0..nd {
dg.push(dec_mv(c)?);
}
let ng = c.leb128()?;
let mut gc = Vec::with_capacity(ng);
for _ in 0..ng {
gc.push(dec_geomclass(c)?);
}
let nc = c.leb128()?;
let mut co = Vec::with_capacity(nc);
for _ in 0..nc {
co.push(dec_construction(c)?);
}
let probe = match c.u8()? {
0 => None,
1 => Some(dec_probe(c)?),
t => {
return Err(CodecError::InvalidTag {
context: "Option<ProbeSpec>",
tag: t,
})
}
};
Ok(Governance {
sig,
derived_gens: dg,
geom_classes: gc,
constructions: co,
probe,
transform_rules: vec![],
})
}
fn enc_snapshot(b: &mut Vec<u8>, s: &GeoitSnapshot) {
enc_mv(b, &s.mv);
enc_gov(b, &s.governance);
enc_predicate(b, &s.predicate);
enc_phase(b, &s.phase);
enc_readings(b, &s.readings);
enc_profile(b, &s.profile);
enc_proof(b, &s.proof);
}
fn dec_snapshot(c: &mut Cur) -> Result<GeoitSnapshot, CodecError> {
let mv = dec_mv(c)?;
let governance = dec_gov(c)?;
let predicate = dec_predicate(c)?;
let phase = dec_phase(c)?;
let readings = dec_readings(c)?;
let profile = dec_profile(c)?;
let proof = dec_proof(c)?;
Ok(GeoitSnapshot {
mv,
governance,
predicate,
phase,
readings,
profile,
proof,
})
}
fn enc_profile(b: &mut Vec<u8>, p: &GeneratorProfile) {
wu64(b, p.i_participation);
wu64(b, p.d_participation);
wu64(b, p.h_participation);
}
fn dec_profile(c: &mut Cur) -> Result<GeneratorProfile, CodecError> {
Ok(GeneratorProfile {
i_participation: c.u64le()?,
d_participation: c.u64le()?,
h_participation: c.u64le()?,
})
}
fn enc_proof(b: &mut Vec<u8>, p: &ProofTerm) {
match p {
ProofTerm::Checked { class_index } => {
b.push(0);
wleb(b, *class_index);
}
ProofTerm::Derived {
rule_name,
input_proofs,
} => {
b.push(1);
enc_string(b, rule_name);
wleb(b, input_proofs.len());
for ip in input_proofs {
enc_proof(b, ip);
}
}
}
}
fn dec_proof(c: &mut Cur) -> Result<ProofTerm, CodecError> {
let tag = c.u8()?;
match tag {
0 => Ok(ProofTerm::Checked {
class_index: c.leb128()?,
}),
1 => {
let name = dec_string(c)?;
let n = c.leb128()?;
let mut proofs = Vec::with_capacity(n);
for _ in 0..n {
proofs.push(Box::new(dec_proof(c)?));
}
Ok(ProofTerm::Derived {
rule_name: name,
input_proofs: proofs,
})
}
_ => Err(CodecError::InvalidTag {
context: "ProofTerm",
tag,
}),
}
}
fn enc_string(b: &mut Vec<u8>, s: &str) {
wleb(b, s.len());
b.extend_from_slice(s.as_bytes());
}
fn dec_string(c: &mut Cur) -> Result<String, CodecError> {
let len = c.leb128()?;
let bytes = c.bytes(len)?;
String::from_utf8(bytes.to_vec())
.map_err(|_| CodecError::InvalidData("invalid UTF-8 in string".into()))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::scalar::Rat;
#[test]
fn leb128_roundtrip() {
for &v in &[0usize, 1, 127, 128, 255, 16384, 1_000_000] {
let mut b = Vec::new();
wleb(&mut b, v);
let mut c = Cur::new(&b);
assert_eq!(c.leb128().unwrap(), v);
}
}
#[test]
fn rat_roundtrip() {
for r in [Rat::ZERO, Rat::ONE, Rat::new(3, 7), Rat::new(-5, 13)] {
let mut b = Vec::new();
enc_rat(&mut b, &r);
let mut c = Cur::new(&b);
assert_eq!(dec_rat(&mut c).unwrap(), r);
}
}
#[test]
fn scalar_variants_roundtrip() {
let cases: Vec<Scalar> = vec![
Scalar::Rat(Rat::new(42, 13)),
Scalar::Radical(RadicalElement::sqrt(Rat::from(5))),
Scalar::Radical(RadicalElement::sqrt(Rat::from(7))),
];
for s in &cases {
let mut b = Vec::new();
enc_scalar(&mut b, s);
let mut c = Cur::new(&b);
assert_eq!(dec_scalar(&mut c).unwrap(), *s);
}
}
#[test]
fn bladekey_roundtrip() {
for bk in [
BladeKey::SCALAR,
BladeKey::generator(0),
BladeKey::from_sorted(&[0, 2, 4]),
BladeKey::pseudoscalar(5),
] {
let mut b = Vec::new();
enc_bladekey(&mut b, &bk);
let mut c = Cur::new(&b);
assert_eq!(dec_bladekey(&mut c).unwrap(), bk);
}
}
#[test]
fn mv_roundtrip() {
let mv = Mv::from_rat_terms(&[(0b001, Rat::from(3)), (0b010, Rat::new(1, 2))]);
let mut b = Vec::new();
enc_mv(&mut b, &mv);
let mut c = Cur::new(&b);
assert_eq!(dec_mv(&mut c).unwrap(), mv);
}
#[test]
fn expr_roundtrip() {
let e = Expr::Add(
Box::new(Expr::Mul(Expr::param(0), Expr::gen(1))),
Box::new(Expr::Literal(Scalar::from(5i64))),
);
let mut b = Vec::new();
enc_expr(&mut b, &e);
let mut c = Cur::new(&b);
let d = dec_expr(&mut c).unwrap();
let mut b2 = Vec::new();
enc_expr(&mut b2, &d);
assert_eq!(b, b2, "Expr roundtrip: re-encoded bytes should match");
}
#[test]
fn phase_roundtrip() {
for p in [Phase::Deliberation, Phase::Evaluation, Phase::Commitment] {
let mut b = Vec::new();
enc_phase(&mut b, &p);
let mut c = Cur::new(&b);
assert_eq!(dec_phase(&mut c).unwrap(), p);
}
}
#[test]
fn governance_roundtrip() {
let gov = Governance {
sig: Signature::new(0, 0, 3).unwrap(),
derived_gens: vec![],
geom_classes: vec![GeomClass::grades_only(&[1])],
constructions: vec![Construction {
class_index: 0,
arity: 3,
body: Expr::Add(
Box::new(Expr::Mul(Expr::param(0), Expr::gen(0))),
Box::new(Expr::Mul(Expr::param(1), Expr::gen(1))),
),
}],
probe: None,
transform_rules: vec![],
};
let bytes = encode_governance(&gov);
let dec = decode_governance(&bytes).unwrap();
assert_eq!(dec.sig, gov.sig);
assert_eq!(dec.geom_classes.len(), 1);
assert_eq!(dec.constructions.len(), 1);
assert_eq!(dec.constructions[0].arity, 3);
assert!(dec.probe.is_none());
}
#[test]
fn snapshot_full_roundtrip() {
let mv = Mv::from_rat_terms(&[(0b001, Rat::from(3)), (0b010, Rat::from(4))]);
let snap = GeoitSnapshot {
mv: mv.clone(),
governance: Governance {
sig: Signature::new(0, 0, 2).unwrap(),
derived_gens: vec![],
geom_classes: vec![],
constructions: vec![],
probe: None,
transform_rules: vec![],
},
predicate: Predicate::new(0, &[], &[], vec![], vec![], false),
phase: Phase::Commitment,
readings: ReadingRules {
extractions: vec![
ExtractionMap::Coefficient(0b001),
ExtractionMap::Coefficient(0b010),
],
},
profile: GeneratorProfile::EMPTY,
proof: ProofTerm::Checked { class_index: 0 },
};
let bytes = encode(&snap);
assert_eq!(&bytes[..5], b"GEOIT");
assert_eq!(bytes[5], 2); let dec = decode(&bytes).unwrap();
assert_eq!(dec.mv, snap.mv);
assert_eq!(dec.phase, snap.phase);
assert_eq!(dec.readings.extractions.len(), 2);
}
#[test]
fn bad_magic() {
assert!(matches!(decode(b"WRONG12345"), Err(CodecError::BadMagic)));
}
#[test]
fn bad_version() {
let mut b = Vec::new();
b.extend_from_slice(MAGIC);
b.push(99);
assert!(matches!(
decode(&b),
Err(CodecError::UnsupportedVersion(99))
));
}
#[test]
fn truncated() {
let mut b = Vec::new();
b.extend_from_slice(MAGIC);
b.push(VERSION);
assert!(matches!(decode(&b), Err(CodecError::UnexpectedEof)));
}
}