UNPKG

mina-attestations

Version:
317 lines 10.6 kB
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