mina-attestations
Version:
Private Attestations on Mina
317 lines • 10.6 kB
JavaScript
import { Bool, Field, Provable, PublicKey } from 'o1js';
import { ProvableType } from "./o1js-missing.js";
import { assert, assertHasProperty } from "./util.js";
import { NestedProvable } from "./nested.js";
import { DynamicArray } from "./dynamic/dynamic-array.js";
import { extractProperty } from "./dynamic/dynamic-record.js";
import { hashDynamicWithPrefix } from "./dynamic/dynamic-hash.js";
import { Imported } from "./credential-imported.js";
import { Numeric, numericMaximumType, } from "./dynamic/gadgets-numeric.js";
export { Node, Operation };
export { root };
const Operation = {
owner: { type: 'owner' },
constant(data) {
return { type: 'constant', data };
},
issuer,
issuerPublicKey,
verificationKeyHash,
publicInput,
property,
record,
equals,
equalsOneOf,
lessThan,
lessThanEq,
add,
sub,
mul,
div,
and,
or,
not,
hash,
hashWithPrefix,
ifThenElse,
compute,
};
const Node = {
eval: evalNode,
evalType: evalNodeType,
};
function evalNode(root, node) {
switch (node.type) {
case 'constant':
return node.data;
case 'root':
return root;
// credential operations
case 'owner':
return root.owner;
case 'credential':
return assertCredential(root, node).data;
case 'issuer':
return assertCredential(root, node).issuer;
case 'issuerPublicKey':
return assertNativeCredential(root, node).witness.issuer;
case 'verificationKeyHash':
return assertImportedCredential(root, node).witness.vk.hash;
case 'publicInput':
return assertImportedCredential(root, node).witness.proof
.publicInput;
case 'property': {
let inner = evalNode(root, node.inner);
return extractProperty(inner, node.key);
}
case 'record': {
let result = {};
for (let key in node.data) {
result[key] = evalNode(root, node.data[key]);
}
return result;
}
case 'equals': {
let left = evalNode(root, node.left);
let right = evalNode(root, node.right);
let bool = Provable.equal(ProvableType.fromValue(left), left, right);
return bool;
}
case 'equalsOneOf': {
let input = evalNode(root, node.input);
let type = NestedProvable.get(NestedProvable.fromValue(input));
let options;
if (Array.isArray(node.options)) {
options = node.options.map((i) => evalNode(root, i));
}
else {
options = evalNode(root, node.options);
}
if (options instanceof DynamicArray.Base) {
let bool = options.reduce(Bool, Bool(false), (acc, o) => acc.or(Provable.equal(type, input, o)));
return bool;
}
let bools = options.map((o) => Provable.equal(type, input, o));
return bools.reduce(Bool.or);
}
case 'lessThan': {
let left = evalNode(root, node.left);
let right = evalNode(root, node.right);
return Numeric.lessThan(left, right);
}
case 'lessThanEq': {
let left = evalNode(root, node.left);
let right = evalNode(root, node.right);
return Numeric.lessThanOrEqual(left, right);
}
case 'add': {
let left = evalNode(root, node.left);
let right = evalNode(root, node.right);
return Numeric.add(left, right);
}
case 'sub': {
let left = evalNode(root, node.left);
let right = evalNode(root, node.right);
return Numeric.subtract(left, right);
}
case 'mul': {
let left = evalNode(root, node.left);
let right = evalNode(root, node.right);
return Numeric.multiply(left, right);
}
case 'div': {
let left = evalNode(root, node.left);
let right = evalNode(root, node.right);
return Numeric.divide(left, right);
}
case 'and': {
let inputs = node.inputs.map((i) => evalNode(root, i));
return inputs.reduce(Bool.and);
}
case 'or': {
let left = evalNode(root, node.left);
let right = evalNode(root, node.right);
return left.or(right);
}
case 'not': {
let inner = evalNode(root, node.inner);
return inner.not();
}
case 'hash': {
let inputs = node.inputs.map((i) => evalNode(root, i));
return hashDynamicWithPrefix(node.prefix, ...inputs);
}
case 'ifThenElse': {
let condition = evalNode(root, node.condition);
let thenNode = evalNode(root, node.thenNode);
let elseNode = evalNode(root, node.elseNode);
let result = Provable.if(condition, thenNode, elseNode);
return result;
}
case 'compute': {
const computationInputs = node.inputs.map((input) => evalNode(root, input));
return node.computation(...computationInputs);
}
}
}
function evalNodeType(rootType, node) {
switch (node.type) {
case 'constant':
return ProvableType.fromValue(node.data);
case 'root':
return rootType;
// credential operations
case 'owner':
return PublicKey;
case 'credential':
return assertCredentialType(rootType, node).data;
case 'issuer':
return Field;
case 'issuerPublicKey':
return PublicKey;
case 'verificationKeyHash':
return Field;
case 'publicInput': {
let spec = assertCredentialType(rootType, node);
return Imported.publicInputType(spec);
}
case 'property': {
// TODO would be nice to get inner types of structs more easily
let inner = evalNodeType(rootType, node.inner);
// case 1: inner is a provable type
if (ProvableType.isProvableType(inner)) {
let innerValue = ProvableType.synthesize(inner);
assertHasProperty(innerValue, node.key);
let value = innerValue[node.key];
return ProvableType.fromValue(value);
}
// case 2: inner is a record of provable types
return inner[node.key];
}
case 'equals':
case 'equalsOneOf':
case 'lessThan':
case 'lessThanEq':
case 'and':
case 'or':
case 'not':
return Bool;
case 'hash':
return Field;
case 'add':
case 'sub':
case 'mul':
case 'div':
let leftType = evalNodeType(rootType, node.left);
let rightType = evalNodeType(rootType, node.right);
return numericMaximumType(leftType, rightType);
case 'ifThenElse':
let thenType = evalNodeType(rootType, node.thenNode);
return thenType; // the two must be the same
case 'record': {
let result = {};
for (let key in node.data) {
result[key] = evalNodeType(rootType, node.data[key]);
}
return result;
}
case 'compute': {
return node.outputType;
}
}
}
// Node constructors
function root(inputs) {
return { type: 'root', input: inputs };
}
function property(node, key) {
return { type: 'property', key, inner: node };
}
function record(nodes) {
return { type: 'record', data: nodes };
}
function equals(left, right) {
return { type: 'equals', left, right };
}
function equalsOneOf(input, options) {
return { type: 'equalsOneOf', input, options };
}
function lessThan(left, right) {
return { type: 'lessThan', left, right };
}
function lessThanEq(left, right) {
return { type: 'lessThanEq', left, right };
}
function add(left, right) {
return { type: 'add', left, right };
}
function sub(left, right) {
return { type: 'sub', left, right };
}
function mul(left, right) {
return { type: 'mul', left, right };
}
function div(left, right) {
return { type: 'div', left, right };
}
function and(...inputs) {
return { type: 'and', inputs };
}
function or(left, right) {
return { type: 'or', left, right };
}
function not(inner) {
return { type: 'not', inner };
}
function hash(...inputs) {
return { type: 'hash', inputs };
}
function hashWithPrefix(prefix, ...inputs) {
return { type: 'hash', inputs, prefix };
}
function ifThenElse(condition, thenNode, elseNode) {
return { type: 'ifThenElse', condition, thenNode, elseNode };
}
function compute(inputs, outputType, computation) {
return {
type: 'compute',
inputs: inputs,
computation: computation,
outputType,
};
}
// credential operations
function issuer(credential) {
return { type: 'issuer', credentialKey: credential.credentialKey };
}
function issuerPublicKey({ credentialType, credentialKey, }) {
assert(credentialType === 'native', '`issuerPublicKey` is only available on signed credentials');
return { type: 'issuerPublicKey', credentialKey };
}
function verificationKeyHash({ credentialType, credentialKey, }) {
assert(credentialType === 'imported', '`verificationKeyHash` is only available on imported credentials');
return { type: 'verificationKeyHash', credentialKey };
}
function publicInput({ credentialType, credentialKey, }) {
assert(credentialType === 'imported', '`publicInput` is only available on imported credentials');
return { type: 'publicInput', credentialKey };
}
function assertCredential(root, credential) {
assertHasProperty(root, credential.credentialKey);
return root[credential.credentialKey];
}
function assertCredentialType(rootType, credential) {
assertHasProperty(rootType, credential.credentialKey);
return rootType[credential.credentialKey];
}
function assertNativeCredential(root, credential) {
let cred = assertCredential(root, credential);
assert(cred.witness?.type === 'native');
return cred;
}
function assertImportedCredential(root, credential) {
let cred = assertCredential(root, credential);
assert(cred.witness?.type === 'imported');
return cred;
}
//# sourceMappingURL=operation.js.map