Skip to content

Commit

Permalink
Merge pull request #1471 from o1-labs/fix/circuit-with-new-provables
Browse files Browse the repository at this point in the history
Fix Circuit for newer provable types
  • Loading branch information
mitschabaude committed Feb 29, 2024
2 parents 451e734 + d90dae7 commit 64a4beb
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
### Fixed

- Mitigate security hazard of deploying token contracts https://github.com/o1-labs/o1js/issues/1439
- Make `Circuit` handle types with a `.provable` property (like those used in ECDSA) https://github.com/o1-labs/o1js/pull/1471
- To support offchain, non-Pickles proofs of ECDSA signatures

## [0.16.1](https://github.com/o1-labs/o1js/compare/834a44002...3b5f7c7)

Expand Down
45 changes: 45 additions & 0 deletions src/examples/circuit/ecdsa.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
Circuit,
circuitMain,
public_,
Crypto,
createEcdsa,
createForeignCurve,
Bytes,
assert,
} from 'o1js';

export { Secp256k1, Ecdsa, Bytes32, Reserves };

class Secp256k1 extends createForeignCurve(Crypto.CurveParams.Secp256k1) {}
class Ecdsa extends createEcdsa(Secp256k1) {}
class Bytes32 extends Bytes(32) {}

class Reserves extends Circuit {
@circuitMain
static main(
@public_ message: Bytes32,
signature: Ecdsa,
publicKey: Secp256k1
) {
assert(signature.verify(message, publicKey));
}
}

console.time('generateKeypair');
let kp = await Reserves.generateKeypair();
console.timeEnd('generateKeypair');

let message = Bytes32.random();
let privateKey = Secp256k1.Scalar.random();
let publicKey = Secp256k1.generator.scale(privateKey);
let signature = Ecdsa.sign(message.toBytes(), privateKey.toBigInt());

console.time('prove');
let proof = await Reserves.prove([signature, publicKey], [message], kp);
console.timeEnd('prove');

console.time('verify');
let isValid = await Reserves.verify([message], kp.verificationKey(), proof);
assert(isValid, 'verifies');
console.timeEnd('verify');
21 changes: 14 additions & 7 deletions src/lib/circuit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,20 +266,27 @@ function circuitMain(
};
}

type ProvableInputPure<T> = ProvablePure<T> | { provable: ProvablePure<T> };

// TODO support auxiliary data
function provableFromTuple(typs: ProvablePure<any>[]): ProvablePure<any> {
function provableFromTuple(
inputTypes: ProvableInputPure<any>[]
): ProvablePure<any> {
let types = inputTypes.map((t) => ('provable' in t ? t.provable : t));
return {
sizeInFields: () => {
return typs.reduce((acc, typ) => acc + typ.sizeInFields(), 0);
return types.reduce((acc, type) => acc + type.sizeInFields(), 0);
},

toFields: (t: Array<any>) => {
if (t.length !== typs.length) {
throw new Error(`typOfArray: Expected ${typs.length}, got ${t.length}`);
if (t.length !== types.length) {
throw new Error(
`typOfArray: Expected ${types.length}, got ${t.length}`
);
}
let res = [];
for (let i = 0; i < t.length; ++i) {
res.push(...typs[i].toFields(t[i]));
res.push(...types[i].toFields(t[i]));
}
return res;
},
Expand All @@ -291,7 +298,7 @@ function provableFromTuple(typs: ProvablePure<any>[]): ProvablePure<any> {
fromFields: (xs: Array<any>) => {
let offset = 0;
let res: Array<any> = [];
typs.forEach((typ) => {
types.forEach((typ) => {
const n = typ.sizeInFields();
res.push(typ.fromFields(xs.slice(offset, offset + n)));
offset += n;
Expand All @@ -300,7 +307,7 @@ function provableFromTuple(typs: ProvablePure<any>[]): ProvablePure<any> {
},

check(xs: Array<any>) {
typs.forEach((typ, i) => (typ as any).check(xs[i]));
types.forEach((typ, i) => (typ as any).check(xs[i]));
},
};
}

0 comments on commit 64a4beb

Please sign in to comment.