Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
10 changes: 10 additions & 0 deletions crates/iota-framework-snapshot/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,15 @@
"0x000000000000000000000000000000000000000000000000000000000000000b",
"0x000000000000000000000000000000000000000000000000000000000000107a"
]
},
"5": {
"git_revision": "9aa26f09a38e",
"package_ids": [
"0x0000000000000000000000000000000000000000000000000000000000000001",
"0x0000000000000000000000000000000000000000000000000000000000000002",
"0x0000000000000000000000000000000000000000000000000000000000000003",
"0x000000000000000000000000000000000000000000000000000000000000000b",
"0x000000000000000000000000000000000000000000000000000000000000107a"
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ module iota::groth16 {
// Error if the given curve is not supported
const EInvalidCurve: u64 = 1;

#[allow(unused_const)]
// Error if the number of public inputs given exceeds the max.
const ETooManyPublicInputs: u64 = 2;

// Error if a public input does not have the correct length.
const EInvalidScalar: u64 = 3;

// We need to set an upper bound on the number of public inputs to avoid a DoS attack.
const MaxPublicInputs: u64 = 8; // This must match the corresponding constant in the native verify function.

/// Represents an elliptic curve construction to be used in the verifier. Currently we support BLS12-381 and BN254.
/// This should be given as the first parameter to `prepare_verifying_key` or `verify_groth16_proof`.
public struct Curve has store, copy, drop {
Expand Down Expand Up @@ -62,7 +67,11 @@ module iota::groth16 {
}

/// Creates a `PublicProofInputs` wrapper from bytes.
/// Creates a `PublicProofInputs` wrapper from bytes. The `bytes` parameter should be a concatenation of a number of
/// 32 bytes scalar field elements to be used as public inputs in little-endian format to a circuit.
public fun public_proof_inputs_from_bytes(bytes: vector<u8>): PublicProofInputs {
assert!(bytes.length() % 32 == 0, EInvalidScalar);
assert!(bytes.length() / 32 <= MaxPublicInputs, ETooManyPublicInputs);
PublicProofInputs { bytes }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ module iota::random {
}

/// Create a generator. Can be used to derive up to MAX_U16 * 32 random bytes.
///
/// Using randomness can be error-prone if you don't observe the subtleties in its correct use, for example, randomness
/// dependent code might be exploitable to attacks that carefully set the gas budget
/// in a way that breaks security. For more information, see:
/// https://docs.iota.org/developer/advanced/onchain-randomness
public fun new_generator(r: &Random, ctx: &mut TxContext): RandomGenerator {
let inner = load_inner(r);
let seed = hmac_sha3_256(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ module iota::groth16_tests {
assert!(vk_bytes == expected_vk_bytes);
}

#[test]
#[expected_failure(abort_code = groth16::EInvalidScalar)]
fun test_invalid_public_inputs() {
let public_inputs_too_short = vector[x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849", x"1234"].flatten();
groth16::public_proof_inputs_from_bytes(public_inputs_too_short);
}

#[test]
#[expected_failure(abort_code = groth16::EInvalidVerifyingKey)]
fun test_prepare_verifying_key_invalid_bls12381() {
Expand Down Expand Up @@ -61,33 +68,27 @@ module iota::groth16_tests {
let invalid_pvk = groth16::pvk_from_bytes(vk_bytes, alpha_bytes, gamma_bytes, delta_bytes);
assert!(groth16::verify_groth16_proof(&curve, &invalid_pvk, &inputs, &proof) == false);

// Invalid public inputs bytes.
let invalid_inputs = groth16::public_proof_inputs_from_bytes(x"cf");
assert!(groth16::verify_groth16_proof(&curve, &pvk, &invalid_inputs, &proof) == false);

// Invalid proof bytes.
let invalid_proof = groth16::proof_points_from_bytes(x"4a");
assert!(groth16::verify_groth16_proof(&curve, &pvk, &inputs, &invalid_proof) == false);
}

#[test]
#[expected_failure(abort_code = groth16::ETooManyPublicInputs)]
fun test_too_many_public_inputs_bls12381() {
let curve = bls12381();

let vk_bytes = x"ada3c24e8c2e63579cc03fd1f112a093a17fc8ab0ff6eee7e04cab7bf8e03e7645381f309ec113309e05ac404c77ac7c8585d5e4328594f5a70a81f6bd4f29073883ee18fd90e2aa45d0fc7376e81e2fdf5351200386f5732e58eb6ff4d318dc";
let alpha_bytes = x"8b0f85a9e7d929244b0af9a35af10717bd667b6227aae37a6d336e815fb0d850873e0d87968345a493b2d31aa8aa400d9820af1d35fa862d1b339ea1f98ac70db7faa304bff120a151a1741d782d08b8f1c1080d4d2f3ebee63ac6cadc666605be306de0973be38fbbf0f54b476bbb002a74ff9506a2b9b9a34b99bfa7481a84a2c9face7065c19d7069cc5738c5350b886a5eeebe656499d2ffb360afc7aff20fa9ee689fb8b46863e90c85224e8f597bf323ad4efb02ee96eb40221fc89918a2c740eabd2886476c7f247a3eb34f0106b3b51cf040e2cdcafea68b0d8eecabf58b5aa2ece3d86259cf2dfa3efab1170c6eb11948826def533849b68335d76d60f3e16bb5c629b1c24df2bdd1a7f13c754d7fe38617ecd7783504e4615e5c13168185cc08de8d63a0f7032ab7e82ff78cf0bc46a84c98f2d95bb5af355cbbe525c44d5c1549c169dfe119a219dbf9038ec73729d187bd0e3ed369e4a2ec2be837f3dcfd958aea7110627d2c0192d262f17e722509c17196005b646a556cf010ef9bd2a2a9b937516a5ecdee516e77d14278e96bc891b630fc833dda714343554ae127c49460416430b7d4f048d08618058335dec0728ad37d10dd9d859c385a38673e71cc98e8439da0accc29de5c92d3c3dc98e199361e9f7558e8b0a2a315ccc5a72f54551f07fad6f6f4615af498aba98aea01a13a4eb84667fd87ee9782b1d812a03f8814f042823a7701238d0fec1e7dec2a26ffea00330b5c7930e95138381435d2a59f51313a48624e30b0a685e357874d41a0a19d83f7420c1d9c04";
let gamma_bytes = x"b675d1ff988116d1f2965d3c0c373569b74d0a1762ea7c4f4635faa5b5a8fa198a2a2ce6153f390a658dc9ad01a415491747e9de7d5f493f59cf05a52eb46eaac397ffc47aef1396cf0d8b75d0664077ea328ad6b63284b42972a8f11c523a60";
let delta_bytes = x"8229cb9443ef1fb72887f917f500e2aef998717d91857bcb92061ecd74d1d24c2b2b282736e8074e4316939b4c9853c117aa08ed49206860d648818b2cccb526585f5790161b1730d39c73603b482424a27bba891aaa6d99f3025d3df2a6bd42";
let pvk = groth16::pvk_from_bytes(vk_bytes, alpha_bytes, gamma_bytes, delta_bytes);

let inputs_bytes = x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849";
let inputs = groth16::public_proof_inputs_from_bytes(inputs_bytes);

let proof_bytes = x"a29981304df8e0f50750b558d4de59dbc8329634b81c986e28e9fff2b0faa52333b14a1f7b275b029e13499d1f5dd8ab955cf5fa3000a097920180381a238ce12df52207597eade4a365a6872c0a19a39c08a9bfb98b69a15615f90cc32660180ca32e565c01a49b505dd277713b1eae834df49643291a3601b11f56957bde02d5446406d0e4745d1bd32c8ccb8d8e80b877712f5f373016d2ecdeebb58caebc7a425b8137ebb1bd0c5b81c1d48151b25f0f24fe9602ba4e403811fb17db6f14";
let proof = groth16::proof_points_from_bytes(proof_bytes);

groth16::verify_groth16_proof(&curve, &pvk, &inputs, &proof);
fun test_too_many_public_inputs() {
// We give 9 inputs which exceeds the limit of 8
let inputs_bytes = vector[
x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849",
x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849",
x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849",
x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849",
x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849",
x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849",
x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849",
x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849",
x"440758042e68b76a376f2fecf3a5a8105edb194c3e774e5a760140305aec8849"
].flatten();
groth16::public_proof_inputs_from_bytes(inputs_bytes);
}

#[test]
Expand Down Expand Up @@ -120,6 +121,13 @@ module iota::groth16_tests {
groth16::prepare_verifying_key(&bn254(), &invalid_vk);
}

#[test]
#[expected_failure(abort_code = groth16::EInvalidScalar)]
fun test_invalid_public_inputs_bn254() {
let public_inputs_too_short = vector[x"3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a", x"1234"].flatten();
groth16::public_proof_inputs_from_bytes(public_inputs_too_short);
}

#[test]
fun test_verify_groth_16_proof_bn254() {
let curve = bn254();
Expand All @@ -144,33 +152,8 @@ module iota::groth16_tests {
let invalid_pvk = groth16::pvk_from_bytes(vk_bytes, alpha_bytes, gamma_bytes, delta_bytes);
assert!(groth16::verify_groth16_proof(&curve, &invalid_pvk, &inputs, &proof) == false);

// Invalid public inputs bytes.
let invalid_inputs = groth16::public_proof_inputs_from_bytes(x"cf");
assert!(groth16::verify_groth16_proof(&curve, &pvk, &invalid_inputs, &proof) == false);

// Invalid proof bytes.
let invalid_proof = groth16::proof_points_from_bytes(x"4a");
assert!(groth16::verify_groth16_proof(&curve, &pvk, &inputs, &invalid_proof) == false);
}

#[test]
#[expected_failure(abort_code = groth16::ETooManyPublicInputs)]
fun test_too_many_public_inputs_bn254() {
let curve = bn254();

let vk_bytes = x"e8324a3242be5193eb38cca8761691ce061e89ce86f1fce8fd7ef40808f12da3c67d9ed5667c841f956e11adbbe240ddf37a1e3a4a890600dc88f608b897898e";
let alpha_bytes = x"51e6d72cd3b0914dd232653f84e7971d3e5bbcde6b47ff8d6c05277e579f1c1eb2fe30aa252c63950de6ea00dd21a1027f6d130357e47c31fafeca0d31e19406231df42bc11ce376f8cf75135d9074f081c242c31f198d151ec69ec37d67cc2b12542cb306a7823c8b194f13672176c6ee8266b2a0c9f57a5dbdb2278046b511d44e715a3ebe02ec2e1cf493c1b1ada84676e234134a6da5a552f61d4e905e15c0dc58a3414d74304775de5ba8571128f3548d269b51fdc08d5b646fd9157e0a2bc0c4bec5a9a6048d17d1d6cd941b4d459f1de0c7c1d417f33995d2a8dd670b91f0baaccaaf2802100901711885026a5ec97fbbb801000d0d01185651947c1900e336921d07eb16d0e25a2192829540ad5eeb1c498ba9c6316e16807a55dc2b9a7f3dea2e4a2f485ed1295a96d6ca86851842b3a22f83507f93ac66a1dc341d5d22f592527d8ea5c12db16bbabe24b76b3e1baf825c8dcf147be369fd8c5300fd77d0aa8dce730e4e7442c93c4890023f3a266c9fbc90ebbf72825e798c4c00";
let gamma_bytes = x"240a80664919b9f7490209cff12bfd81c32c272607dc004661c792082cbe282ef826f56a3822ebd72345f86c7ee9872e23f10d1f2dbf43f8aca5dc2ceb5388a5";
let delta_bytes = x"f755df8c90edab48ac5adafef6a5a461902217f392e3aa4c34c0462b700c18164f79018778755980d491647de11ecc51fda2cc17171c4b44485ec37ccd23a69b";
let pvk = groth16::pvk_from_bytes(vk_bytes, alpha_bytes, gamma_bytes, delta_bytes);

// We give 9 equal inputs which exceeds the limit of 8
let inputs_bytes = x"3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a3fd7c445c6845a9399d1a7b8394c16373399a037786c169f16219359d3be840a";
let inputs = groth16::public_proof_inputs_from_bytes(inputs_bytes);

let proof_bytes = x"dd2ef02e57d6a282df6b7f36c134ab7e55c2e04c5b8cbd7831be18e0e7224623ae8bd6c41637c10cbd02f5e68de6394461f417895ddd264d6f0ddacf68c6cd02feb8881f0efa599139a6faf4223dd8743777c4346cba52322eb466af96f2be9f813af1450f84d6f8029804f60cac1add70ad1a3d4226404f84f4022dc18caa0f";
let proof = groth16::proof_points_from_bytes(proof_bytes);

groth16::verify_groth16_proof(&curve, &pvk, &inputs, &proof);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
/// Defines a fixed-point numeric type with a 32-bit integer part and
/// a 32-bit fractional part.

#[deprecated(note = b"Use `std::uq32_32` instead. If you need to convert from a `FixedPoint32` to a `UQ32_32`, you can use the `std::fixed_point32::get_raw_value` with `std::uq32_32::from_raw_value`.")]
module std::fixed_point32 {

/// Define a fixed-point numeric type with 32 fractional bits.
Expand Down
5 changes: 5 additions & 0 deletions crates/iota-framework/packages/move-stdlib/sources/u32.move
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,9 @@ module std::u32 {
public macro fun do_eq($stop: u32, $f: |u32|) {
std::macros::do_eq!($stop, $f)
}

/// Maximum value for a `u32`
public macro fun max_value(): u32 {
0xFFFF_FFFF
}
}
5 changes: 5 additions & 0 deletions crates/iota-framework/packages/move-stdlib/sources/u64.move
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,9 @@ module std::u64 {
public macro fun do_eq($stop: u64, $f: |u64|) {
std::macros::do_eq!($stop, $f)
}

/// Maximum value for a `u64`
public macro fun max_value(): u64 {
0xFFFF_FFFF_FFFF_FFFF
}
}
158 changes: 158 additions & 0 deletions crates/iota-framework/packages/move-stdlib/sources/uq32_32.move
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// Copyright (c) Mysten Labs, Inc.
// Modifications Copyright (c) 2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

/// Defines an unsigned, fixed-point numeric type with a 32-bit integer part and a 32-bit fractional
/// part. The notation `uq32_32` and `UQ32_32` is based on
/// [Q notation](https://en.wikipedia.org/wiki/Q_(number_format)). `q` indicates it a fixed-point
/// number. The `u` prefix indicates it is unsigned. The `32_32` suffix indicates the number of
/// bits, where the first number indicates the number of bits in the integer part, and the second
/// the number of bits in the fractional part--in this case 32 bits for each.
module std::uq32_32;

#[error]
const EDenominator: vector<u8> = b"Quotient specified with a zero denominator";

#[error]
const EQuotientTooSmall: vector<u8> =
b"Quotient specified is too small, and is outside of the supported range";

#[error]
const EQuotientTooLarge: vector<u8> =
b"Quotient specified is too large, and is outside of the supported range";

#[error]
const EOverflow: vector<u8> = b"Overflow from an arithmetic operation";

#[error]
const EDivisionByZero: vector<u8> = b"Division by zero";

/// A fixed-point numeric type with 32 integer bits and 32 fractional bits, represented by an
/// underlying 64 bit value. This is a binary representation, so decimal values may not be exactly
/// representable, but it provides more than 9 decimal digits of precision both before and after the
/// decimal point (18 digits total).
public struct UQ32_32(u64) has copy, drop, store;

/// Create a fixed-point value from a quotient specified by its numerator and denominator.
/// `from_quotient` and `from_int` should be preferred over using `from_raw`.
/// Unless the denominator is a power of two, fractions can not be represented accurately,
/// so be careful about rounding errors.
/// Aborts if the denominator is zero.
/// Aborts if the input is non-zero but so small that it will be represented as zero, e.g. smaller
/// than 2^{-32}.
/// Aborts if the input is too large, e.g. larger than or equal to 2^32.
public fun from_quotient(numerator: u64, denominator: u64): UQ32_32 {
assert!(denominator != 0, EDenominator);
// Scale the numerator to have 64 fractional bits and the denominator to have 32 fractional
// bits, so that the quotient will have 32 fractional bits.
let scaled_numerator = numerator as u128 << 64;
let scaled_denominator = denominator as u128 << 32;
let quotient = scaled_numerator / scaled_denominator;
// The quotient can only be zero if the numerator is also zero.
assert!(quotient != 0 || numerator == 0, EQuotientTooSmall);
// Return the quotient as a fixed-point number. We first need to check whether the cast
// can succeed.
assert!(quotient <= std::u64::max_value!() as u128, EQuotientTooLarge);
UQ32_32(quotient as u64)
}

/// Create a fixed-point value from an integer.
/// `from_int` and `from_quotient` should be preferred over using `from_raw`.
public fun from_int(integer: u32): UQ32_32 {
UQ32_32((integer as u64) << 32)
}

/// Add two fixed-point numbers, `a + b`.
/// Aborts if the sum overflows.
public fun add(a: UQ32_32, b: UQ32_32): UQ32_32 {
let sum = a.0 as u128 + (b.0 as u128);
assert!(sum <= std::u64::max_value!() as u128, EOverflow);
UQ32_32(sum as u64)
}

/// Subtract two fixed-point numbers, `a - b`.
/// Aborts if `a < b`.
public fun sub(a: UQ32_32, b: UQ32_32): UQ32_32 {
assert!(a.0 >= b.0, EOverflow);
UQ32_32(a.0 - b.0)
}

/// Multiply two fixed-point numbers, truncating any fractional part of the product.
/// Aborts if the product overflows.
public fun mul(a: UQ32_32, b: UQ32_32): UQ32_32 {
UQ32_32(int_mul(a.0, b))
}

/// Divide two fixed-point numbers, truncating any fractional part of the quotient.
/// Aborts if the divisor is zero.
/// Aborts if the quotient overflows.
public fun div(a: UQ32_32, b: UQ32_32): UQ32_32 {
UQ32_32(int_div(a.0, b))
}

/// Convert a fixed-point number to an integer, truncating any fractional part.
public fun to_int(a: UQ32_32): u32 {
(a.0 >> 32) as u32
}

/// Multiply a `u64` integer by a fixed-point number, truncating any fractional part of the product.
/// Aborts if the product overflows.
public fun int_mul(val: u64, multiplier: UQ32_32): u64 {
// The product of two 64 bit values has 128 bits, so perform the
// multiplication with u128 types and keep the full 128 bit product
// to avoid losing accuracy.
let unscaled_product = val as u128 * (multiplier.0 as u128);
// The unscaled product has 32 fractional bits (from the multiplier)
// so rescale it by shifting away the low bits.
let product = unscaled_product >> 32;
// Check whether the value is too large.
assert!(product <= std::u64::max_value!() as u128, EOverflow);
product as u64
}

/// Divide a `u64` integer by a fixed-point number, truncating any fractional part of the quotient.
/// Aborts if the divisor is zero.
/// Aborts if the quotient overflows.
public fun int_div(val: u64, divisor: UQ32_32): u64 {
// Check for division by zero.
assert!(divisor.0 != 0, EDivisionByZero);
// First convert to 128 bits and then shift left to
// add 32 fractional zero bits to the dividend.
let scaled_value = val as u128 << 32;
let quotient = scaled_value / (divisor.0 as u128);
// Check whether the value is too large.
assert!(quotient <= std::u64::max_value!() as u128, EOverflow);
quotient as u64
}

/// Less than or equal to. Returns `true` if and only if `a <= a`.
public fun le(a: UQ32_32, b: UQ32_32): bool {
a.0 <= b.0
}

/// Less than. Returns `true` if and only if `a < b`.
public fun lt(a: UQ32_32, b: UQ32_32): bool {
a.0 < b.0
}

/// Greater than or equal to. Returns `true` if and only if `a >= b`.
public fun ge(a: UQ32_32, b: UQ32_32): bool {
a.0 >= b.0
}

/// Greater than. Returns `true` if and only if `a > b`.
public fun gt(a: UQ32_32, b: UQ32_32): bool {
a.0 > b.0
}

/// Accessor for the raw u64 value. Can be paired with `from_raw` to perform less common operations
/// on the raw values directly.
public fun to_raw(a: UQ32_32): u64 {
a.0
}

/// Accessor for the raw u64 value. Can be paired with `to_raw` to perform less common operations
/// on the raw values directly.
public fun from_raw(raw_value: u64): UQ32_32 {
UQ32_32(raw_value)
}
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,13 @@ module std::vector {
acc
}

/// Concatenate the vectors of `v` into a single vector, keeping the order of the elements.
public fun flatten<T>(v: vector<vector<T>>): vector<T> {
let mut r = vector[];
v.do!(|u| r.append(u));
r
}

/// Whether any element in the vector `v` satisfies the predicate `f`.
/// If the vector is empty, returns `false`.
public macro fun any<$T>($v: &vector<$T>, $f: |&$T| -> bool): bool {
Expand Down
Loading