Skip to content

Commit af67452

Browse files
committed
also support Fp, Fp2
1 parent 21cfc2e commit af67452

File tree

4 files changed

+104
-18
lines changed

4 files changed

+104
-18
lines changed

soroban-sdk-macros/src/map_type.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ use syn::{
88
Type, TypePath, TypeTuple,
99
};
1010

11-
const G1_SERIALIZED_SIZE: u32 = 96; // Must match soroban_sdk::crypto::bls21_381::G1_SERIALIZED_SIZE.
12-
const G2_SERIALIZED_SIZE: u32 = 192; // Must match soroban_sdk::crypto::bls21_381::G2_SERIALIZED_SIZE.
11+
// These constants' values must match the definitions of the constants with the
12+
// same names in soroban_sdk::crypto::bls12_381.
13+
pub const FP_SERIALIZED_SIZE: u32 = 48;
14+
pub const FP2_SERIALIZED_SIZE: u32 = FP_SERIALIZED_SIZE * 2;
15+
pub const G1_SERIALIZED_SIZE: u32 = FP_SERIALIZED_SIZE * 2;
16+
pub const G2_SERIALIZED_SIZE: u32 = FP2_SERIALIZED_SIZE * 2;
1317

1418
#[allow(clippy::too_many_lines)]
1519
pub fn map_type(t: &Type, allow_hash: bool) -> Result<ScSpecTypeDef, Error> {
@@ -40,9 +44,9 @@ pub fn map_type(t: &Type, allow_hash: bool) -> Result<ScSpecTypeDef, Error> {
4044
"Address" => Ok(ScSpecTypeDef::Address),
4145
"Timepoint" => Ok(ScSpecTypeDef::Timepoint),
4246
"Duration" => Ok(ScSpecTypeDef::Duration),
43-
// The BLS types `G1Affine`, `G2Affine`, and `Fr` are represented in
44-
// the contract's interface by their underlying data types: I.e.
45-
// G1Affine/G2Affine => BytesN<N>, Fr => U256. This approach
47+
// The BLS types defined below are represented in the contract's
48+
// interface by their underlying data types, i.e.
49+
// Fp/Fp2/G1Affine/G2Affine => BytesN<N>, Fr => U256. This approach
4650
// simplifies integration with contract development tooling, as it
4751
// avoids introducing new spec types for these BLS constructs.
4852
//
@@ -58,6 +62,12 @@ pub fn map_type(t: &Type, allow_hash: bool) -> Result<ScSpecTypeDef, Error> {
5862
// Idiom. For more details, see the tracking issue for supporting
5963
// type aliases:
6064
// https://github.com/stellar/rs-soroban-sdk/issues/1063
65+
"Fp" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
66+
n: FP_SERIALIZED_SIZE,
67+
})),
68+
"Fp2" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
69+
n: FP2_SERIALIZED_SIZE,
70+
})),
6171
"G1Affine" => Ok(ScSpecTypeDef::BytesN(ScSpecTypeBytesN {
6272
n: G1_SERIALIZED_SIZE,
6373
})),

soroban-sdk/src/tests/crypto_bls12_381.rs

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use soroban_sdk::{
33
bytes, bytesn, contract, contractimpl,
44
crypto::bls12_381::{Bls12_381, Fp, Fp2, Fr, G1Affine, G2Affine},
55
env::EnvTestConfig,
6-
vec, Address, Bytes, Env, Vec, U256,
6+
vec, Address, Bytes, BytesN, Env, Vec, U256,
77
};
88

99
#[test]
@@ -243,14 +243,13 @@ pub struct Contract;
243243

244244
#[contractimpl(crate_path = "crate")]
245245
impl Contract {
246-
pub fn g1_mul_with(
247-
env: Env,
248-
contract_id: Address,
249-
p: crate::BytesN<96>,
250-
s: U256,
251-
) -> crate::BytesN<96> {
246+
pub fn g1_mul_with(env: Env, contract_id: Address, p: BytesN<96>, s: U256) -> BytesN<96> {
252247
blscontract::Client::new(&env, &contract_id).g1_mul(&p, &s)
253248
}
249+
250+
pub fn verify_with(env: Env, contract_id: Address, proof: blscontract::DummyProof) -> bool {
251+
blscontract::Client::new(&env, &contract_id).dummy_verify(&proof)
252+
}
254253
}
255254

256255
#[test]
@@ -276,4 +275,24 @@ fn test_invoke_contract() {
276275
let inf = G1Affine::from_bytes(bytesn!(&e, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000));
277276
let res = client.g1_mul_with(&bls_contract_id, &g1.as_bytes(), &zero.to_u256());
278277
assert_eq!(&res, inf.as_bytes());
278+
279+
let fp_val = Fp::from_bytes(bytesn!(&e, 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001));
280+
let fp2_val = Fp2::from_bytes(bytesn!(&e, 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001));
281+
let g1_point = G1Affine::from_bytes(bytesn!(&e, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1));
282+
let g2_point = G2Affine::from_bytes(bytesn!(&e, 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801));
283+
let fr_scalar = Fr::from_bytes(bytesn!(
284+
&e,
285+
0x0000000000000000000000000000000000000000000000000000000000000001
286+
));
287+
288+
let proof = blscontract::DummyProof {
289+
fp: fp_val.to_bytes(),
290+
fp2: fp2_val.to_bytes(),
291+
g1: g1_point.to_bytes(),
292+
g2: g2_point.to_bytes(),
293+
fr: fr_scalar.to_u256(),
294+
};
295+
296+
let res = client.verify_with(&bls_contract_id, &proof);
297+
assert!(!res);
279298
}

soroban-sdk/src/testutils/arbitrary.rs

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,10 @@ mod objects {
320320

321321
use crate::xdr::{Int256Parts, ScVal, UInt256Parts};
322322
use crate::{
323-
crypto::bls12_381::{Fr, G1Affine, G2Affine},
323+
crypto::bls12_381::{
324+
Fp, Fp2, Fr, G1Affine, G2Affine, FP2_SERIALIZED_SIZE, FP_SERIALIZED_SIZE,
325+
G1_SERIALIZED_SIZE, G2_SERIALIZED_SIZE,
326+
},
324327
Address, Bytes, BytesN, Duration, Map, String, Symbol, Timepoint, Val, Vec, I256, U256,
325328
};
326329

@@ -682,10 +685,46 @@ mod objects {
682685
}
683686
}
684687

688+
// For Fp (48 bytes)
689+
#[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
690+
pub struct ArbitraryFp {
691+
bytes: [u8; FP_SERIALIZED_SIZE],
692+
}
693+
694+
impl SorobanArbitrary for Fp {
695+
type Prototype = ArbitraryFp;
696+
}
697+
698+
impl TryFromVal<Env, ArbitraryFp> for Fp {
699+
type Error = ConversionError;
700+
701+
fn try_from_val(env: &Env, v: &ArbitraryFp) -> Result<Self, Self::Error> {
702+
Ok(Fp::from_array(env, &v.bytes))
703+
}
704+
}
705+
706+
// For Fp2 (96 bytes)
707+
#[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
708+
pub struct ArbitraryFp2 {
709+
bytes: [u8; FP2_SERIALIZED_SIZE],
710+
}
711+
712+
impl SorobanArbitrary for Fp2 {
713+
type Prototype = ArbitraryFp2;
714+
}
715+
716+
impl TryFromVal<Env, ArbitraryFp2> for Fp2 {
717+
type Error = ConversionError;
718+
719+
fn try_from_val(env: &Env, v: &ArbitraryFp2) -> Result<Self, Self::Error> {
720+
Ok(Fp2::from_array(env, &v.bytes))
721+
}
722+
}
723+
685724
// For G1Affine (96 bytes)
686725
#[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
687726
pub struct ArbitraryG1Affine {
688-
bytes: [u8; 96],
727+
bytes: [u8; G1_SERIALIZED_SIZE],
689728
}
690729

691730
impl SorobanArbitrary for G1Affine {
@@ -720,7 +759,7 @@ mod objects {
720759
// For G2Affine (192 bytes)
721760
#[derive(Arbitrary, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
722761
pub struct ArbitraryG2Affine {
723-
bytes: [u8; 192],
762+
bytes: [u8; G2_SERIALIZED_SIZE],
724763
}
725764

726765
impl SorobanArbitrary for G2Affine {

tests/bls/src/lib.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
#![no_std]
22
use soroban_sdk::{
33
contract, contractimpl, contracttype,
4-
crypto::bls12_381::{Fr, G1Affine, G2Affine},
5-
Env,
4+
crypto::bls12_381::{Fp, Fp2, Fr, G1Affine, G2Affine},
5+
log, Env,
66
};
77

88
#[derive(Clone)]
99
#[contracttype]
1010
pub struct DummyProof {
11+
pub fp: Fp,
12+
pub fp2: Fp2,
1113
pub g1: G1Affine,
1214
pub g2: G2Affine,
1315
pub fr: Fr,
@@ -26,7 +28,15 @@ impl Contract {
2628
env.crypto().bls12_381().g2_mul(&p, &s)
2729
}
2830

31+
// A dummy proof just to run all the inputs through host functions
32+
// to validate these types are compatible with contracts
2933
pub fn dummy_verify(env: Env, proof: DummyProof) -> bool {
34+
let g1 = env.crypto().bls12_381().map_fp_to_g1(&proof.fp);
35+
let in1 = env.crypto().bls12_381().g1_is_in_subgroup(&g1);
36+
log!(&env, "`map_fp_to_g1` result is in subgroup: ", in1);
37+
let g2 = env.crypto().bls12_381().map_fp2_to_g2(&proof.fp2);
38+
let in2 = env.crypto().bls12_381().g2_is_in_subgroup(&g2);
39+
log!(&env, "`map_fp2_to_g2` result is in subgroup: ", in2);
3040
let g1_mul = env.crypto().bls12_381().g1_mul(&proof.g1, &proof.fr);
3141
let g2_mul = env.crypto().bls12_381().g2_mul(&proof.g2, &proof.fr);
3242
let vp1 = soroban_sdk::Vec::from_array(&env, [g1_mul]);
@@ -82,6 +92,8 @@ mod test {
8292
let contract_id = env.register(Contract, ());
8393
let client = ContractClient::new(&env, &contract_id);
8494

95+
let fp = Fp::from_bytes(bytesn!(&env, 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001));
96+
let fp2 = Fp2::from_bytes(bytesn!(&env, 0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001));
8597
// Use generator points
8698
let g1 = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1));
8799
let g2 = G2Affine::from_bytes(bytesn!(&env, 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801));
@@ -92,7 +104,13 @@ mod test {
92104
0x0000000000000000000000000000000000000000000000000000000000000001
93105
));
94106

95-
let proof = DummyProof { g1, g2, fr };
107+
let proof = DummyProof {
108+
fp,
109+
fp2,
110+
g1,
111+
g2,
112+
fr,
113+
};
96114
let res = client.dummy_verify(&proof);
97115
assert!(!res); // The pairing of generator points multiplied by the same scalar should not be the identity
98116
}

0 commit comments

Comments
 (0)