1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use std::sync::Arc;
use super::CoreCircuit;
use crate::{errors::ExpressionError, ConstrainedValue, GroupType, Integer};
use leo_asg::{FunctionBody, Span};
use snarkvm_gadgets::algorithms::prf::Blake2sGadget;
use snarkvm_models::{
curves::{Field, PrimeField},
gadgets::{
algorithms::PRFGadget,
r1cs::ConstraintSystem,
utilities::{uint::UInt8, ToBytesGadget},
},
};
pub struct Blake2s;
fn unwrap_argument<F: Field + PrimeField, G: GroupType<F>>(arg: ConstrainedValue<F, G>) -> Vec<UInt8> {
if let ConstrainedValue::Array(args) = arg {
assert_eq!(args.len(), 32);
args.into_iter()
.map(|item| {
if let ConstrainedValue::Integer(Integer::U8(item)) = item {
item
} else {
panic!("illegal non-u8 type in blake2s call");
}
})
.collect()
} else {
panic!("illegal non-array type in blake2s call");
}
}
impl<F: Field + PrimeField, G: GroupType<F>> CoreCircuit<F, G> for Blake2s {
fn call_function<CS: ConstraintSystem<F>>(
&self,
cs: &mut CS,
function: Arc<FunctionBody>,
span: &Span,
target: Option<ConstrainedValue<F, G>>,
mut arguments: Vec<ConstrainedValue<F, G>>,
) -> Result<ConstrainedValue<F, G>, ExpressionError> {
assert_eq!(arguments.len(), 2);
assert!(function.function.name.borrow().name == "hash");
assert!(target.is_none());
let input = unwrap_argument(arguments.remove(1));
let seed = unwrap_argument(arguments.remove(0));
let digest =
Blake2sGadget::check_evaluation_gadget(cs.ns(|| "blake2s hash"), &seed[..], &input[..]).map_err(|e| {
ExpressionError::cannot_enforce("Blake2s check evaluation gadget".to_owned(), e, span.clone())
})?;
Ok(ConstrainedValue::Array(
digest
.to_bytes(cs)
.map_err(|e| ExpressionError::cannot_enforce("Vec<UInt8> ToBytes".to_owned(), e, span.clone()))?
.into_iter()
.map(Integer::U8)
.map(ConstrainedValue::Integer)
.collect(),
))
}
}