@cryptoeconomicslab/ovm-transpiler
Advanced tools
Comparing version 0.2.3 to 0.2.4
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
const primitives_1 = require("@cryptoeconomicslab/primitives"); | ||
const utils = tslib_1.__importStar(require("./utils")); | ||
@@ -8,3 +9,3 @@ const presetPredicateTable = { | ||
name: 'SignedBy', | ||
translate: (p) => { | ||
translate: (p, suffix) => { | ||
return { | ||
@@ -15,7 +16,7 @@ type: 'PropertyNode', | ||
`signatures,KEY,\${${p.inputs[0]}}`, | ||
'sig', | ||
`sig${suffix}`, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'IsValidSignature', | ||
inputs: [p.inputs[0], 'sig', p.inputs[1], '$secp256k1'] | ||
inputs: [p.inputs[0], `sig${suffix}`, p.inputs[1], '$secp256k1'] | ||
} | ||
@@ -28,3 +29,3 @@ ] | ||
name: 'IncludedAt', | ||
translate: (p) => { | ||
translate: (p, suffix) => { | ||
return { | ||
@@ -35,3 +36,3 @@ type: 'PropertyNode', | ||
`su.block\${${p.inputs[3]}}.range\${${p.inputs[1]}},RANGE,\${${p.inputs[2]}}`, | ||
'inclusionProof', | ||
`proof${suffix}`, | ||
{ | ||
@@ -44,3 +45,3 @@ type: 'PropertyNode', | ||
p.inputs[2], | ||
'inclusionProof', | ||
`proof${suffix}`, | ||
p.inputs[3] | ||
@@ -52,35 +53,14 @@ ] | ||
} | ||
} | ||
}; | ||
const zero = '0000000000000000000000000000000000000000000000000000000000000000'; | ||
const presetQuantifierTable = { | ||
IsLessThan: { | ||
name: 'IsLessThan', | ||
translate: (p) => { | ||
const quantifier = p.inputs[0]; | ||
const variable = p.inputs[1]; | ||
return { | ||
hint: `range,NUMBER,${zero}\${${quantifier.inputs[0]}}`, | ||
properties: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'IsLessThan', | ||
inputs: [variable, quantifier.inputs[0]] | ||
} | ||
] | ||
}; | ||
} | ||
}, | ||
Range: { | ||
name: 'Range', | ||
translate: (p) => { | ||
const quantifier = p.inputs[0]; | ||
const variable = p.inputs[1]; | ||
IsWithinRange: { | ||
name: 'IsWithinRange', | ||
translate: (p, suffix) => { | ||
return { | ||
hint: `range,NUMBER,\${${quantifier.inputs[0]}}\${${quantifier.inputs[1]}}`, | ||
properties: [ | ||
type: 'PropertyNode', | ||
predicate: 'And', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'IsLessThan', | ||
inputs: [quantifier.inputs[0], variable] | ||
inputs: [p.inputs[1], p.inputs[0]] | ||
}, | ||
@@ -90,3 +70,3 @@ { | ||
predicate: 'IsLessThan', | ||
inputs: [variable, quantifier.inputs[1]] | ||
inputs: [p.inputs[0], p.inputs[2]] | ||
} | ||
@@ -97,47 +77,56 @@ ] | ||
}, | ||
SU: { | ||
name: 'SU', | ||
translate: (p) => { | ||
const quantifier = p.inputs[0]; | ||
const variable = p.inputs[1]; | ||
if (quantifier.inputs.length == 2) { | ||
return { | ||
hint: `su.block\${${quantifier.inputs[0]}}.range\${${quantifier.inputs[1]}},ITER,${zero}`, | ||
properties: [] | ||
}; | ||
} | ||
else if (quantifier.inputs.length == 3) { | ||
return { | ||
hint: `su.block\${${quantifier.inputs[0]}}.range\${${quantifier.inputs[1]}},RANGE,\${${quantifier.inputs[2]}}`, | ||
properties: [ | ||
IncludedWithin: { | ||
name: 'IncludedWithin', | ||
translate: (p, suffix) => { | ||
const inputs = [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'ThereExistsSuchThat', | ||
inputs: [ | ||
`su.block\${${p.inputs[1]}}.range\${${p.inputs[2]}},RANGE,\${${p.inputs[3]}}`, | ||
`proof${suffix}`, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'IncludedWithin', | ||
predicate: 'VerifyInclusion', | ||
inputs: [ | ||
variable, | ||
quantifier.inputs[1], | ||
quantifier.inputs[2], | ||
quantifier.inputs[0] | ||
p.inputs[0], | ||
p.inputs[0] + '.0', | ||
p.inputs[0] + '.1', | ||
`proof${suffix}`, | ||
p.inputs[1] | ||
] | ||
} | ||
] | ||
}; | ||
}, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Equal', | ||
inputs: [p.inputs[0] + '.0', p.inputs[2]] | ||
} | ||
]; | ||
if (p.inputs.length > 3) { | ||
inputs.push({ | ||
type: 'PropertyNode', | ||
predicate: 'IsContained', | ||
inputs: [p.inputs[0] + '.1', p.inputs[3]] | ||
}); | ||
} | ||
else { | ||
throw new Error('invalid number of quantifier inputs'); | ||
} | ||
return { | ||
type: 'PropertyNode', | ||
predicate: 'And', | ||
inputs: inputs | ||
}; | ||
} | ||
}, | ||
Tx: { | ||
name: 'Tx', | ||
translate: (p) => { | ||
const quantifier = p.inputs[0]; | ||
const variable = p.inputs[1]; | ||
IsTx: { | ||
name: 'IsTx', | ||
translate: (p, suffix) => { | ||
return { | ||
hint: `tx.block\${${quantifier.inputs[2]}}.range\${${quantifier.inputs[0]}},RANGE,\${${quantifier.inputs[1]}}`, | ||
properties: [ | ||
type: 'PropertyNode', | ||
predicate: 'And', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Equal', | ||
inputs: [variable + '.address', '$TransactionAddress'] | ||
inputs: [p.inputs[0] + '.address', '$TransactionAddress'] | ||
}, | ||
@@ -147,3 +136,3 @@ { | ||
predicate: 'Equal', | ||
inputs: [variable + '.0', quantifier.inputs[0]] | ||
inputs: [p.inputs[0] + '.0', p.inputs[1]] | ||
}, | ||
@@ -153,3 +142,3 @@ { | ||
predicate: 'IsContained', | ||
inputs: [variable + '.1', quantifier.inputs[1]] | ||
inputs: [p.inputs[0] + '.1', p.inputs[2]] | ||
}, | ||
@@ -159,3 +148,3 @@ { | ||
predicate: 'Equal', | ||
inputs: [variable + '.2', quantifier.inputs[2]] | ||
inputs: [p.inputs[0] + '.2', p.inputs[3]] | ||
} | ||
@@ -167,2 +156,41 @@ ] | ||
}; | ||
const createQuantifier = (name, predicate, hint) => { | ||
return { | ||
name, | ||
translate: (quantifier, variable) => { | ||
return { | ||
hint: hint(quantifier), | ||
property: { | ||
type: 'PropertyNode', | ||
predicate, | ||
inputs: [variable].concat(quantifier.inputs) | ||
} | ||
}; | ||
} | ||
}; | ||
}; | ||
const zero = primitives_1.BigNumber.from(0); | ||
const presetQuantifierTable = { | ||
IsLessThan: createQuantifier('IsLessThan', 'IsLessThan', (quantifier) => { | ||
const encodedZero = ovmContext.coder.encode(zero).toHexString(); | ||
return `range,NUMBER,${encodedZero}-\${${quantifier.inputs[0]}}`; | ||
}), | ||
Range: createQuantifier('Range', 'IsWithinRange', (quantifier) => `range,NUMBER,\${${quantifier.inputs[0]}}\${${quantifier.inputs[1]}}`), | ||
Stored: createQuantifier('Stored', 'IsStored', (quantifier) => `store.\${${quantifier.inputs[0]}},KEY,\${${quantifier.inputs[1]}}`), | ||
Concat: createQuantifier('Concat', 'VerifyConcatenate', (quantifier) => `_,CONCAT,\${${quantifier.inputs[0]}}-\${${quantifier.inputs[1]}}`), | ||
Hash: createQuantifier('Hash', 'IsValidHash', (quantifier) => `_,HASH,\${${quantifier.inputs[0]}}`), | ||
SU: createQuantifier('SU', 'IncludedWithin', (quantifier) => { | ||
if (quantifier.inputs.length == 2) { | ||
const encodedZero = ovmContext.coder.encode(zero).toHexString(); | ||
return `su.block\${${quantifier.inputs[0]}}.range\${${quantifier.inputs[1]}},ITER,${encodedZero}`; | ||
} | ||
else if (quantifier.inputs.length == 3) { | ||
return `su.block\${${quantifier.inputs[0]}}.range\${${quantifier.inputs[1]}},RANGE,\${${quantifier.inputs[2]}}`; | ||
} | ||
else { | ||
throw new Error('invalid number of quantifier inputs'); | ||
} | ||
}), | ||
Tx: createQuantifier('Tx', 'IsTx', (quantifier) => `tx.block\${${quantifier.inputs[2]}}.range\${${quantifier.inputs[0]}},RANGE,\${${quantifier.inputs[1]}}`) | ||
}; | ||
function translateQuantifier(propertyDefs) { | ||
@@ -176,7 +204,7 @@ return propertyDefs.map(translateQuantifierPerPropertyDef); | ||
} | ||
function translateQuantifierPerPropertyNode(p) { | ||
function translateQuantifierPerPropertyNode(p, variableSuffix = 0) { | ||
if (utils.isAtomicProposition(p.predicate)) { | ||
const preset = presetPredicateTable[p.predicate]; | ||
if (preset) { | ||
return preset.translate(p); | ||
return preset.translate(p, (variableSuffix++).toString()); | ||
} | ||
@@ -196,3 +224,3 @@ } | ||
else { | ||
return translateQuantifierPerPropertyNode(i); | ||
return translateQuantifierPerPropertyNode(i, variableSuffix); | ||
} | ||
@@ -210,5 +238,7 @@ }); | ||
if (preset) { | ||
const translated = preset.translate(p); | ||
const quantifier = p.inputs[0]; | ||
const variable = p.inputs[1]; | ||
const translated = preset.translate(quantifier, variable); | ||
p.inputs[0] = translated.hint; | ||
const condition = translated.properties[0]; | ||
const condition = translated.property; | ||
if (condition) { | ||
@@ -222,3 +252,3 @@ p.inputs[2] = { | ||
predicate: 'Not', | ||
inputs: [condition] | ||
inputs: [translateQuantifierPerPropertyNode(condition)] | ||
}, | ||
@@ -239,9 +269,14 @@ p.inputs[2] | ||
if (preset) { | ||
const translated = preset.translate(p); | ||
const quantifier = p.inputs[0]; | ||
const variable = p.inputs[1]; | ||
const translated = preset.translate(quantifier, variable); | ||
p.inputs[0] = translated.hint; | ||
if (translated.properties.length > 0) { | ||
if (translated.property) { | ||
p.inputs[2] = { | ||
type: 'PropertyNode', | ||
predicate: 'And', | ||
inputs: translated.properties.concat([p.inputs[2]]) | ||
inputs: [ | ||
translateQuantifierPerPropertyNode(translated.property), | ||
p.inputs[2] | ||
] | ||
}; | ||
@@ -248,0 +283,0 @@ } |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
const QuantifierTranslater_1 = require("./QuantifierTranslater"); | ||
const coder_1 = tslib_1.__importDefault(require("@cryptoeconomicslab/coder")); | ||
const context_1 = require("@cryptoeconomicslab/context"); | ||
context_1.setupContext({ coder: coder_1.default }); | ||
describe('QuantifierTranslater', () => { | ||
@@ -29,7 +33,7 @@ beforeEach(async () => { }); | ||
'signatures,KEY,${a}', | ||
'sig', | ||
'sig0', | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'IsValidSignature', | ||
inputs: ['a', 'sig', 'b', '$secp256k1'] | ||
inputs: ['a', 'sig0', 'b', '$secp256k1'] | ||
} | ||
@@ -74,3 +78,3 @@ ] | ||
inputs: [ | ||
'range,NUMBER,0000000000000000000000000000000000000000000000000000000000000000${b}', | ||
'range,NUMBER,0x223022-${b}', | ||
'bb', | ||
@@ -100,2 +104,118 @@ { | ||
}); | ||
test('Stored', () => { | ||
const input = [ | ||
{ | ||
name: 'RootTest', | ||
inputDefs: ['block'], | ||
body: { | ||
type: 'PropertyNode', | ||
predicate: 'ForAllSuchThat', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Stored', | ||
inputs: ['$address', 'block'] | ||
}, | ||
'root', | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Foo', | ||
inputs: ['root'] | ||
} | ||
] | ||
} | ||
} | ||
]; | ||
const output = QuantifierTranslater_1.translateQuantifier(input); | ||
expect(output).toStrictEqual([ | ||
{ | ||
name: 'RootTest', | ||
inputDefs: ['block'], | ||
body: { | ||
type: 'PropertyNode', | ||
predicate: 'ForAllSuchThat', | ||
inputs: [ | ||
'store.${$address},KEY,${block}', | ||
'root', | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Or', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Not', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'IsStored', | ||
inputs: ['root', '$address', 'block'] | ||
} | ||
] | ||
}, | ||
{ type: 'PropertyNode', predicate: 'Foo', inputs: ['root'] } | ||
] | ||
} | ||
] | ||
} | ||
} | ||
]); | ||
}); | ||
test('Concat', () => { | ||
const input = [ | ||
{ | ||
name: 'ConcatTest', | ||
inputDefs: ['a', 'b'], | ||
body: { | ||
type: 'PropertyNode', | ||
predicate: 'ForAllSuchThat', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Concat', | ||
inputs: ['a', 'b'] | ||
}, | ||
'bytes', | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Foo', | ||
inputs: ['bytes'] | ||
} | ||
] | ||
} | ||
} | ||
]; | ||
const output = QuantifierTranslater_1.translateQuantifier(input); | ||
expect(output).toStrictEqual([ | ||
{ | ||
name: 'ConcatTest', | ||
inputDefs: ['a', 'b'], | ||
body: { | ||
type: 'PropertyNode', | ||
predicate: 'ForAllSuchThat', | ||
inputs: [ | ||
'_,CONCAT,${a}-${b}', | ||
'bytes', | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Or', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Not', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'VerifyConcatenate', | ||
inputs: ['bytes', 'a', 'b'] | ||
} | ||
] | ||
}, | ||
{ type: 'PropertyNode', predicate: 'Foo', inputs: ['bytes'] } | ||
] | ||
} | ||
] | ||
} | ||
} | ||
]); | ||
}); | ||
test('SU', () => { | ||
@@ -146,4 +266,34 @@ const input = [ | ||
type: 'PropertyNode', | ||
predicate: 'IncludedWithin', | ||
inputs: ['su', 'range', 'block', 'token'] | ||
predicate: 'And', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'ThereExistsSuchThat', | ||
inputs: [ | ||
'su.block${token}.range${range},RANGE,${block}', | ||
'proof0', | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'VerifyInclusion', | ||
inputs: [ | ||
'su', | ||
'su.0', | ||
'su.1', | ||
'proof0', | ||
'token' | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Equal', | ||
inputs: ['su.0', 'range'] | ||
}, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'IsContained', | ||
inputs: ['su.1', 'block'] | ||
} | ||
] | ||
} | ||
@@ -201,20 +351,26 @@ ] | ||
type: 'PropertyNode', | ||
predicate: 'Equal', | ||
inputs: ['tx.address', '$TransactionAddress'] | ||
predicate: 'And', | ||
inputs: [ | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Equal', | ||
inputs: ['tx.address', '$TransactionAddress'] | ||
}, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Equal', | ||
inputs: ['tx.0', 'token'] | ||
}, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'IsContained', | ||
inputs: ['tx.1', 'range'] | ||
}, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Equal', | ||
inputs: ['tx.2', 'block'] | ||
} | ||
] | ||
}, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Equal', | ||
inputs: ['tx.0', 'token'] | ||
}, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'IsContained', | ||
inputs: ['tx.1', 'range'] | ||
}, | ||
{ | ||
type: 'PropertyNode', | ||
predicate: 'Equal', | ||
inputs: ['tx.2', 'block'] | ||
}, | ||
{ type: 'PropertyNode', predicate: 'Foo', inputs: ['tx'] } | ||
@@ -221,0 +377,0 @@ ] |
@@ -30,4 +30,7 @@ "use strict"; | ||
predicate == 'IsValidSignature' || | ||
predicate == 'IsValidHash' || | ||
predicate == 'IsContained' || | ||
predicate == 'VerifyInclusion' || | ||
predicate == 'VerifyConcatenate' || | ||
predicate == 'IsStored' || | ||
predicate == 'IsSameAmount'); | ||
@@ -34,0 +37,0 @@ } |
{ | ||
"name": "@cryptoeconomicslab/ovm-transpiler", | ||
"version": "0.2.3", | ||
"version": "0.2.4", | ||
"description": "OVM transpiler", | ||
@@ -51,6 +51,9 @@ "author": { | ||
"dependencies": { | ||
"@cryptoeconomicslab/coder": "0.0.4", | ||
"@cryptoeconomicslab/context": "0.0.4", | ||
"@cryptoeconomicslab/ovm-parser": "^0.2.3", | ||
"@cryptoeconomicslab/primitives": "0.0.4", | ||
"tslib": "^1.10.0" | ||
}, | ||
"gitHead": "16a79feb8d5b9e1adf22d5e5efc270aab3070249" | ||
"gitHead": "bd563fbf46e82f914f06daa49fc0bfd621e7dec3" | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
124088
1883
5
+ Added@cryptoeconomicslab/coder@0.0.4(transitive)
+ Added@cryptoeconomicslab/context@0.0.4(transitive)
+ Added@cryptoeconomicslab/primitives@0.0.4(transitive)
+ Addedtext-encoding@0.7.0(transitive)