Skip to content

Commit deeb278

Browse files
committed
Add BLS contract test
1 parent a11b21d commit deeb278

File tree

7 files changed

+374
-6
lines changed

7 files changed

+374
-6
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

soroban-sdk/src/crypto/bls12_381.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -466,12 +466,6 @@ impl From<&Fr> for U256Val {
466466
}
467467
}
468468

469-
impl IntoVal<Env, Val> for Fr {
470-
fn into_val(&self, e: &Env) -> Val {
471-
self.0.into_val(e)
472-
}
473-
}
474-
475469
impl TryFromVal<Env, Val> for Fr {
476470
type Error = ConversionError;
477471

@@ -481,6 +475,28 @@ impl TryFromVal<Env, Val> for Fr {
481475
}
482476
}
483477

478+
impl TryFromVal<Env, Fr> for Val {
479+
type Error = ConversionError;
480+
481+
fn try_from_val(_env: &Env, fr: &Fr) -> Result<Self, Self::Error> {
482+
Ok(fr.to_val())
483+
}
484+
}
485+
486+
#[cfg(not(target_family = "wasm"))]
487+
impl From<&Fr> for ScVal {
488+
fn from(v: &Fr) -> Self {
489+
Self::from(&v.0)
490+
}
491+
}
492+
493+
#[cfg(not(target_family = "wasm"))]
494+
impl From<Fr> for ScVal {
495+
fn from(v: Fr) -> Self {
496+
(&v).into()
497+
}
498+
}
499+
484500
impl Eq for Fr {}
485501

486502
impl PartialEq for Fr {

tests/bls/Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[package]
2+
name = "test_bls"
3+
version.workspace = true
4+
authors = ["Stellar Development Foundation <info@stellar.org>"]
5+
license = "Apache-2.0"
6+
edition = "2021"
7+
publish = false
8+
rust-version = "1.84.0"
9+
10+
[lib]
11+
crate-type = ["cdylib"]
12+
doctest = false
13+
14+
[dependencies]
15+
soroban-sdk = {path = "../../soroban-sdk"}
16+
17+
[dev-dependencies]
18+
soroban-sdk = {path = "../../soroban-sdk", features = ["testutils"]}

tests/bls/src/lib.rs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#![no_std]
2+
use soroban_sdk::{
3+
contract, contractimpl, contracttype,
4+
crypto::bls12_381::{Fr, G1Affine, G2Affine},
5+
Env,
6+
};
7+
8+
#[derive(Clone)]
9+
#[contracttype]
10+
pub struct DummyProof {
11+
pub g1: G1Affine,
12+
pub g2: G2Affine,
13+
pub fr: Fr,
14+
}
15+
16+
#[contract]
17+
pub struct Contract;
18+
19+
#[contractimpl]
20+
impl Contract {
21+
pub fn g1_mul(env: Env, p: G1Affine, s: Fr) -> G1Affine {
22+
env.crypto().bls12_381().g1_mul(&p, &s)
23+
}
24+
25+
pub fn g2_mul(env: Env, p: G2Affine, s: Fr) -> G2Affine {
26+
env.crypto().bls12_381().g2_mul(&p, &s)
27+
}
28+
29+
pub fn dummy_verify(env: Env, proof: DummyProof) -> bool {
30+
let g1_mul = env.crypto().bls12_381().g1_mul(&proof.g1, &proof.fr);
31+
let g2_mul = env.crypto().bls12_381().g2_mul(&proof.g2, &proof.fr);
32+
let vp1 = soroban_sdk::Vec::from_array(&env, [g1_mul]);
33+
let vp2 = soroban_sdk::Vec::from_array(&env, [g2_mul]);
34+
env.crypto().bls12_381().pairing_check(vp1, vp2)
35+
}
36+
}
37+
38+
#[cfg(test)]
39+
mod test {
40+
use super::*;
41+
use soroban_sdk::{bytesn, Env};
42+
43+
use crate::{Contract, ContractClient};
44+
45+
#[test]
46+
fn test_g1_mul() {
47+
let env = Env::default();
48+
let contract_id = env.register(Contract, ());
49+
let client = ContractClient::new(&env, &contract_id);
50+
51+
// G1 generator and zero scalar
52+
let g1 = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1));
53+
let zero = Fr::from_bytes(bytesn!(
54+
&env,
55+
0x0000000000000000000000000000000000000000000000000000000000000000
56+
));
57+
let inf = G1Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000));
58+
let res = client.g1_mul(&g1, &zero);
59+
assert_eq!(res, inf);
60+
}
61+
62+
#[test]
63+
fn test_g2_mul() {
64+
let env = Env::default();
65+
let contract_id = env.register(Contract, ());
66+
let client = ContractClient::new(&env, &contract_id);
67+
68+
// G2 generator and zero scalar
69+
let g2 = G2Affine::from_bytes(bytesn!(&env, 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801));
70+
let zero = Fr::from_bytes(bytesn!(
71+
&env,
72+
0x0000000000000000000000000000000000000000000000000000000000000000
73+
));
74+
let inf = G2Affine::from_bytes(bytesn!(&env, 0x400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000));
75+
let res = client.g2_mul(&g2, &zero);
76+
assert_eq!(res, inf);
77+
}
78+
79+
#[test]
80+
fn test_dummy_verify() {
81+
let env = Env::default();
82+
let contract_id = env.register(Contract, ());
83+
let client = ContractClient::new(&env, &contract_id);
84+
85+
// Use generator points
86+
let g1 = G1Affine::from_bytes(bytesn!(&env, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1));
87+
let g2 = G2Affine::from_bytes(bytesn!(&env, 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb80606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801));
88+
89+
// Create a scalar value
90+
let fr = Fr::from_bytes(bytesn!(
91+
&env,
92+
0x0000000000000000000000000000000000000000000000000000000000000001
93+
));
94+
95+
let proof = DummyProof { g1, g2, fr };
96+
let res = client.dummy_verify(&proof);
97+
assert!(!res); // The pairing of generator points multiplied by the same scalar should not be the identity
98+
}
99+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"generators": {
3+
"address": 1,
4+
"nonce": 0
5+
},
6+
"auth": [
7+
[],
8+
[]
9+
],
10+
"ledger": {
11+
"protocol_version": 22,
12+
"sequence_number": 0,
13+
"timestamp": 0,
14+
"network_id": "0000000000000000000000000000000000000000000000000000000000000000",
15+
"base_reserve": 0,
16+
"min_persistent_entry_ttl": 4096,
17+
"min_temp_entry_ttl": 16,
18+
"max_entry_ttl": 6312000,
19+
"ledger_entries": [
20+
[
21+
{
22+
"contract_data": {
23+
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
24+
"key": "ledger_key_contract_instance",
25+
"durability": "persistent"
26+
}
27+
},
28+
[
29+
{
30+
"last_modified_ledger_seq": 0,
31+
"data": {
32+
"contract_data": {
33+
"ext": "v0",
34+
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
35+
"key": "ledger_key_contract_instance",
36+
"durability": "persistent",
37+
"val": {
38+
"contract_instance": {
39+
"executable": {
40+
"wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
41+
},
42+
"storage": null
43+
}
44+
}
45+
}
46+
},
47+
"ext": "v0"
48+
},
49+
4095
50+
]
51+
],
52+
[
53+
{
54+
"contract_code": {
55+
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
56+
}
57+
},
58+
[
59+
{
60+
"last_modified_ledger_seq": 0,
61+
"data": {
62+
"contract_code": {
63+
"ext": "v0",
64+
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
65+
"code": ""
66+
}
67+
},
68+
"ext": "v0"
69+
},
70+
4095
71+
]
72+
]
73+
]
74+
},
75+
"events": []
76+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
{
2+
"generators": {
3+
"address": 1,
4+
"nonce": 0
5+
},
6+
"auth": [
7+
[],
8+
[]
9+
],
10+
"ledger": {
11+
"protocol_version": 22,
12+
"sequence_number": 0,
13+
"timestamp": 0,
14+
"network_id": "0000000000000000000000000000000000000000000000000000000000000000",
15+
"base_reserve": 0,
16+
"min_persistent_entry_ttl": 4096,
17+
"min_temp_entry_ttl": 16,
18+
"max_entry_ttl": 6312000,
19+
"ledger_entries": [
20+
[
21+
{
22+
"contract_data": {
23+
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
24+
"key": "ledger_key_contract_instance",
25+
"durability": "persistent"
26+
}
27+
},
28+
[
29+
{
30+
"last_modified_ledger_seq": 0,
31+
"data": {
32+
"contract_data": {
33+
"ext": "v0",
34+
"contract": "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD2KM",
35+
"key": "ledger_key_contract_instance",
36+
"durability": "persistent",
37+
"val": {
38+
"contract_instance": {
39+
"executable": {
40+
"wasm": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
41+
},
42+
"storage": null
43+
}
44+
}
45+
}
46+
},
47+
"ext": "v0"
48+
},
49+
4095
50+
]
51+
],
52+
[
53+
{
54+
"contract_code": {
55+
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
56+
}
57+
},
58+
[
59+
{
60+
"last_modified_ledger_seq": 0,
61+
"data": {
62+
"contract_code": {
63+
"ext": "v0",
64+
"hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
65+
"code": ""
66+
}
67+
},
68+
"ext": "v0"
69+
},
70+
4095
71+
]
72+
]
73+
]
74+
},
75+
"events": []
76+
}

0 commit comments

Comments
 (0)