-
Notifications
You must be signed in to change notification settings - Fork 11.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Examples/Move] Port remaining Crypto Sui Programmability Examples (#…
…18609) ## Description Port over the following examples from sui_programmability/examples: - crypto/sources/ecdsa.move - crypto/sources/groth16.move - ~games/sources/drand_lib.move~ - ~games/sources/drand_based_lottery.move~ - ~games/sources/drand_based_scratch_card.move~ - games/sources/vdf_based_lottery.move Modernising and cleaning them up in the process: - Applying wrapping consistently at 100 characters, and cleaning up comments. - Removing unnecessary use of `entry` functions, including returning values instead of transfering to sender in some cases. - Using receiver functions where possible. - Standardising file order and adding titles for sections. - Standardising use of doc comments vs regular comments. - Using clever errors. This marks the final set of examples to be moved out of sui-programmability, which will then be deleted. ## Test plan ``` sui-framework-tests$ cargo nextest run -- run_examples_move_unit_tests ``` ## Stack - #18525 - #18526 - #18557 - #18558 - #18595 --- ## Release notes Check each box that your changes affect. If none of the boxes relate to your changes, release notes aren't required. For each box you select, include information after the relevant heading that describes the impact of your changes that a user might notice and any actions they must take to implement updates. - [ ] Protocol: - [ ] Nodes (Validators and Full nodes): - [ ] Indexer: - [ ] JSON-RPC: - [ ] GraphQL: - [ ] CLI: - [ ] Rust SDK: --------- Co-authored-by: Ronny Roland <[email protected]>
- Loading branch information
1 parent
aae6f5c
commit d43a7ad
Showing
8 changed files
with
677 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "ecdsa_k1" | ||
version = "0.0.1" | ||
edition = "2024.beta" | ||
|
||
[dependencies] | ||
Sui = { local = "../../../../crates/sui-framework/packages/sui-framework" } | ||
|
||
[addresses] | ||
ecdsa_k1 = "0x0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
/// A basic ECDSA utility contract to do the following: | ||
/// | ||
/// 1) Hash a piece of data using Keccak256, output an object with hashed data. | ||
/// 2) Recover a Secp256k1 signature to its public key, output an | ||
/// object with the public key. | ||
/// 3) Verify a Secp256k1 signature, produce an event for whether it is verified. | ||
module ecdsa_k1::example { | ||
use sui::ecdsa_k1; | ||
use sui::event; | ||
|
||
// === Object Types === | ||
|
||
/// Object that holds the output data | ||
public struct Output has key, store { | ||
id: UID, | ||
value: vector<u8> | ||
} | ||
|
||
// == Event Types === | ||
|
||
/// Event on whether the signature is verified | ||
public struct VerifiedEvent has copy, drop { | ||
is_verified: bool, | ||
} | ||
|
||
// === Public Functions === | ||
|
||
/// Hash the data using Keccak256, output an object with the hash to recipient. | ||
public fun keccak256( | ||
data: vector<u8>, | ||
recipient: address, | ||
ctx: &mut TxContext, | ||
) { | ||
let hashed = Output { | ||
id: object::new(ctx), | ||
value: sui::hash::keccak256(&data), | ||
}; | ||
// Transfer an output data object holding the hashed data to the recipient. | ||
transfer::public_transfer(hashed, recipient) | ||
} | ||
|
||
/// Recover the public key using the signature and message, assuming the signature was produced | ||
/// over the Keccak256 hash of the message. Output an object with the recovered pubkey to | ||
/// recipient. | ||
public fun ecrecover( | ||
signature: vector<u8>, | ||
msg: vector<u8>, | ||
recipient: address, | ||
ctx: &mut TxContext, | ||
) { | ||
let pubkey = Output { | ||
id: object::new(ctx), | ||
value: ecdsa_k1::secp256k1_ecrecover(&signature, &msg, 0), | ||
}; | ||
// Transfer an output data object holding the pubkey to the recipient. | ||
transfer::public_transfer(pubkey, recipient) | ||
} | ||
|
||
/// Recover the Ethereum address using the signature and message, assuming the signature was | ||
/// produced over the Keccak256 hash of the message. Output an object with the recovered address | ||
/// to recipient. | ||
public fun ecrecover_to_eth_address( | ||
mut signature: vector<u8>, | ||
msg: vector<u8>, | ||
recipient: address, | ||
ctx: &mut TxContext, | ||
) { | ||
// Normalize the last byte of the signature to be 0 or 1. | ||
let v = &mut signature[64]; | ||
if (*v == 27) { | ||
*v = 0; | ||
} else if (*v == 28) { | ||
*v = 1; | ||
} else if (*v > 35) { | ||
*v = (*v - 1) % 2; | ||
}; | ||
|
||
// Ethereum signature is produced with Keccak256 hash of the message, so the last param is | ||
// 0. | ||
let pubkey = ecdsa_k1::secp256k1_ecrecover(&signature, &msg, 0); | ||
let uncompressed = ecdsa_k1::decompress_pubkey(&pubkey); | ||
|
||
// Take the last 64 bytes of the uncompressed pubkey. | ||
let mut uncompressed_64 = vector[]; | ||
let mut i = 1; | ||
while (i < 65) { | ||
uncompressed_64.push_back(uncompressed[i]); | ||
i = i + 1; | ||
}; | ||
|
||
// Take the last 20 bytes of the hash of the 64-bytes uncompressed pubkey. | ||
let hashed = sui::hash::keccak256(&uncompressed_64); | ||
let mut addr = vector[]; | ||
let mut i = 12; | ||
while (i < 32) { | ||
addr.push_back(hashed[i]); | ||
i = i + 1; | ||
}; | ||
|
||
let addr_object = Output { | ||
id: object::new(ctx), | ||
value: addr, | ||
}; | ||
|
||
// Transfer an output data object holding the address to the recipient. | ||
transfer::public_transfer(addr_object, recipient) | ||
} | ||
|
||
/// Verified the secp256k1 signature using public key and message assuming Keccak was using when | ||
/// signing. Emit an is_verified event of the verification result. | ||
public fun secp256k1_verify(signature: vector<u8>, public_key: vector<u8>, msg: vector<u8>) { | ||
event::emit(VerifiedEvent { | ||
is_verified: ecdsa_k1::secp256k1_verify(&signature, &public_key, &msg, 0) | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "groth16" | ||
version = "0.0.1" | ||
edition = "2024.beta" | ||
|
||
[dependencies] | ||
Sui = { local = "../../../../crates/sui-framework/packages/sui-framework" } | ||
|
||
[addresses] | ||
groth16 = "0x0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
/// A verifier for the Groth16 zk-SNARK over the BLS12-381 construction. | ||
/// See https://eprint.iacr.org/2016/260.pdf for details. | ||
module groth16::example { | ||
use sui::bls12381; | ||
use sui::group_ops::Element; | ||
|
||
// === Types === | ||
|
||
/// A Groth16 proof. | ||
public struct Proof has drop { | ||
a: Element<bls12381::G1>, | ||
b: Element<bls12381::G2>, | ||
c: Element<bls12381::G1>, | ||
} | ||
|
||
/// A Groth16 verifying key used to verify a zero-knowledge proof. | ||
public struct VerifyingKey has store, drop { | ||
alpha: Element<bls12381::G1>, | ||
beta: Element<bls12381::G2>, | ||
gamma: Element<bls12381::G2>, | ||
gamma_abc: vector<Element<bls12381::G1>>, | ||
delta: Element<bls12381::G2>, | ||
} | ||
|
||
/// A prepared verifying key. This makes verification faster than using the verifying key directly. | ||
public struct PreparedVerifyingKey has store, drop { | ||
alpha_beta: Element<bls12381::GT>, | ||
gamma_neg: Element<bls12381::G2>, | ||
gamma_abc: vector<Element<bls12381::G1>>, | ||
delta_neg: Element<bls12381::G2>, | ||
} | ||
|
||
// === Errors === | ||
|
||
#[error] | ||
const EInvalidNumberOfPublicInputs: vector<u8> = | ||
b"There must be one more public input than gamma_abc entries in the verifying key."; | ||
|
||
// === Public Functions === | ||
|
||
/// Create a new `Proof`. | ||
public fun create_proof( | ||
a: Element<bls12381::G1>, | ||
b: Element<bls12381::G2>, | ||
c: Element<bls12381::G1>, | ||
): Proof { | ||
Proof { a, b, c } | ||
} | ||
|
||
/// Create a new `VerifyingKey`. | ||
public fun create_verifying_key( | ||
alpha: Element<bls12381::G1>, | ||
beta: Element<bls12381::G2>, | ||
gamma: Element<bls12381::G2>, | ||
gamma_abc: vector<Element<bls12381::G1>>, | ||
delta: Element<bls12381::G2>, | ||
): VerifyingKey { | ||
VerifyingKey { alpha, beta, gamma, gamma_abc, delta } | ||
} | ||
|
||
/// Create a PreparedVerifyingKey from a VerifyingKey. This only have to be | ||
/// done once. | ||
public fun prepare(vk: VerifyingKey): PreparedVerifyingKey { | ||
PreparedVerifyingKey { | ||
alpha_beta: bls12381::pairing(&vk.alpha, &vk.beta), | ||
gamma_neg: bls12381::g2_neg(&vk.gamma), | ||
gamma_abc: vk.gamma_abc, | ||
delta_neg: bls12381::g2_neg(&vk.delta), | ||
} | ||
} | ||
|
||
/// Verify a Groth16 proof with some public inputs and a verifying key. | ||
public fun verify( | ||
pvk: &PreparedVerifyingKey, | ||
proof: &Proof, | ||
public_inputs: &vector<Element<bls12381::Scalar>>, | ||
): bool { | ||
let prepared_inputs = prepare_inputs(&pvk.gamma_abc, public_inputs); | ||
let mut lhs = bls12381::pairing(&proof.a, &proof.b); | ||
lhs = bls12381::gt_add(&lhs, &bls12381::pairing(&prepared_inputs, &pvk.gamma_neg)); | ||
lhs = bls12381::gt_add(&lhs, &bls12381::pairing(&proof.c, &pvk.delta_neg)); | ||
lhs == pvk.alpha_beta | ||
} | ||
|
||
// === Helpers === | ||
|
||
fun prepare_inputs( | ||
vk_gamma_abc: &vector<Element<bls12381::G1>>, | ||
public_inputs: &vector<Element<bls12381::Scalar>>, | ||
): Element<bls12381::G1> { | ||
let length = public_inputs.length(); | ||
assert!(length + 1 == vk_gamma_abc.length(), EInvalidNumberOfPublicInputs); | ||
|
||
let mut output = vk_gamma_abc[0]; | ||
let mut i = 0; | ||
while (i < length) { | ||
output = bls12381::g1_add( | ||
&output, | ||
&bls12381::g1_mul(&public_inputs[i], &vk_gamma_abc[i + 1]), | ||
); | ||
i = i + 1; | ||
}; | ||
output | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#[test_only] | ||
module groth16::example_tests { | ||
use sui::bls12381; | ||
use groth16::example::{create_verifying_key, create_proof, verify}; | ||
|
||
#[test] | ||
fun test_verification() { | ||
let vk = create_verifying_key( | ||
bls12381::g1_from_bytes(&x"b58cfc3b0f43d98e7dbe865af692577d52813cb62ef3c355215ec3be2a0355a1ae5da76dd3e626f8a60de1f4a8138dee"), | ||
bls12381::g2_from_bytes(&x"9047b42915b32ef9dffe3acc0121a1450416e7f9791159f165ab0729d744da3ed82cd4822ca1d7fef35147cfd620b59b0ca09db7dff43aab6c71635ba8f86a83f058e9922e5cdacbe21d0e5e855cf1e776a61b272c12272fe526f5ba3b48d579"), | ||
bls12381::g2_from_bytes(&x"ad7c5a6cefcae53a3fbae72662c7c04a2f8e1892cb83615a02b32c31247172b7f317489b84e72f14acaf4f3e9ed18141157c6c1464bf15d957227f75a3c550d6d27f295b41a753340c6eec47b471b2cb8664c84f3e9b725325d3fb8afc6b56d0"), | ||
vector[ | ||
bls12381::g1_from_bytes(&x"b2c9c61ccc28e913284a47c34e60d487869ff423dd574db080d35844f9eddd2b2967141b588a35fa82a278ce39ae6b1a"), | ||
bls12381::g1_from_bytes(&x"9026ae12d58d203b4fc5dfad4968cbf51e43632ed1a05afdcb2e380ee552b036fbefc7780afe9675bcb60201a2421b2c") | ||
], | ||
bls12381::g2_from_bytes(&x"b1294927d02f8e86ac57c3b832f4ecf5e03230445a9a785ac8d25cf968f48cca8881d0c439c7e8870b66567cf611da0c1734316632f39d3125c8cecca76a8661db91cbfae217547ea1fc078a24a1a31555a46765011411094ec649d42914e2f5"), | ||
); | ||
|
||
let public_inputs = vector[ | ||
bls12381::scalar_from_bytes(&x"46722abc81a82d01ac89c138aa01a8223cb239ceb1f02cdaad7e1815eb997ca6") | ||
]; | ||
|
||
let proof = create_proof( | ||
bls12381::g1_from_bytes(&x"9913bdcabdff2cf1e7dea1673c5edba5ed6435df2f2a58d6d9e624609922bfa3976a98d991db333812bf6290a590afaa"), | ||
bls12381::g2_from_bytes(&x"b0265b35af5069593ee88626cf3ba9a0f07699510a25aec3a27048792ab83b3467d6b814d1c09c412c4dcd7656582e6607b72915081c82794ccedf643c27abace5b23a442079d8dcbd0d68dd697b8e0b699a1925a5f2c77f5237efbbbeda3bd0"), | ||
bls12381::g1_from_bytes(&x"b1237cf48ca7aa98507e826aac336b9e24f14133de1923fffac602a1203b795b3037c4c94e7246bacee7b2757ae912e5"), | ||
); | ||
|
||
assert!(vk.prepare().verify(&proof, &public_inputs)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
name = "VDF" | ||
version = "0.0.1" | ||
edition = "2024.beta" | ||
|
||
[dependencies] | ||
Sui = { local = "../../../crates/sui-framework/packages/sui-framework" } | ||
|
||
[addresses] | ||
vdf = "0x0" |
Oops, something went wrong.