builtins_common/bls12_381/
low_level.rs

1// This file is part of Gear.
2
3// Copyright (C) 2025 Gear Technologies Inc.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use super::*;
20use ark_bls12_381::{
21    Bls12_381, G1Projective, G2Projective, g1::Config as G1Config, g2::Config as G2Config,
22};
23use ark_ec::{
24    CurveConfig, VariableBaseMSM,
25    bls12::Bls12Config,
26    hashing::{HashToCurve, curve_maps::wb, map_to_curve_hasher::MapToCurveBasedHasher},
27    pairing::{MillerLoopOutput, Pairing},
28    short_weierstrass::{Affine as SWAffine, Projective as SWProjective, SWCurveConfig},
29};
30use ark_ff::fields::field_hashers::DefaultFieldHasher;
31use ark_scale::{
32    HOST_CALL,
33    scale::{Decode, Encode},
34};
35use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate};
36use gear_core::limited::LimitedStr;
37use sha2;
38
39type ArkScaleLocal<T> = ark_scale::ArkScale<T, HOST_CALL>;
40const _: () = assert!(HOST_CALL == ark_scale::make_usage(Compress::No, Validate::No));
41type ArkScaleProjective<T> = ark_scale::hazmat::ArkScaleProjective<T>;
42
43/// Implementation of the bls12-381 operations, intended to be used
44/// directly.
45///
46/// Current impl is also used as a base impl for host-call based impl.
47/// The methods impl are considered to be low-level. To actually execute
48/// bls12-381 operations separate functions defined in the `builtins_common::bls12_381`
49/// must be used.
50pub struct Bls12_381OpsLowLevel;
51
52/// Basically, copies impl of bls12_381 operations from `sp-crypto-ec-utils` crate
53impl Bls12_381Ops for Bls12_381OpsLowLevel {
54    fn multi_miller_loop(g1: Vec<u8>, g2: Vec<u8>) -> Result<Vec<u8>, BuiltinActorError> {
55        let a = Self::decode::<Vec<<Bls12_381 as Pairing>::G1Affine>>(g1)?;
56        let b = Self::decode::<Vec<<Bls12_381 as Pairing>::G2Affine>>(g2)?;
57        let res = Bls12_381::multi_miller_loop(a, b);
58
59        Ok(Self::encode(res.0))
60    }
61
62    fn final_exponentiation(f: Vec<u8>) -> Result<Vec<u8>, BuiltinActorError> {
63        let f = Self::decode::<<Bls12_381 as Pairing>::TargetField>(f)?;
64        let res = Bls12_381::final_exponentiation(MillerLoopOutput(f)).ok_or(
65            BuiltinActorError::Custom(LimitedStr::from_small_str("Final exponentiation failed")),
66        )?;
67
68        Ok(Self::encode(res.0))
69    }
70
71    fn msm_g1(bases: Vec<u8>, scalars: Vec<u8>) -> Result<Vec<u8>, BuiltinActorError> {
72        Self::msm_sw::<G1Config>(bases, scalars)
73    }
74
75    fn msm_g2(bases: Vec<u8>, scalars: Vec<u8>) -> Result<Vec<u8>, BuiltinActorError> {
76        Self::msm_sw::<G2Config>(bases, scalars)
77    }
78
79    fn projective_mul_g1(base: Vec<u8>, scalar: Vec<u8>) -> Result<Vec<u8>, BuiltinActorError> {
80        Self::projective_mul_sw::<G1Config>(base, scalar)
81    }
82
83    fn projective_mul_g2(base: Vec<u8>, scalar: Vec<u8>) -> Result<Vec<u8>, BuiltinActorError> {
84        Self::projective_mul_sw::<G2Config>(base, scalar)
85    }
86
87    fn aggregate_g1(points: Vec<u8>) -> Result<Vec<u8>, BuiltinActorError> {
88        let points = Self::decode::<Vec<G1Projective>>(points)?;
89
90        let point_first = points.first().ok_or(BuiltinActorError::EmptyG1PointsList)?;
91
92        let point_aggregated = points
93            .iter()
94            .skip(1)
95            .fold(*point_first, |aggregated, point| aggregated + *point);
96
97        Ok(Self::encode(point_aggregated))
98    }
99
100    fn map_to_g2affine(message: Vec<u8>) -> Result<Vec<u8>, BuiltinActorError> {
101        type WBMap = wb::WBMap<<ark_bls12_381::Config as Bls12Config>::G2Config>;
102
103        // Domain Separation Tag for signatures on G2.
104        const DST_G2: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_";
105
106        let mapper =
107            MapToCurveBasedHasher::<G2Projective, DefaultFieldHasher<sha2::Sha256>, WBMap>::new(
108                DST_G2,
109            )
110            .map_err(|_| BuiltinActorError::MapperCreationError)?;
111
112        let point = mapper
113            .hash(&message)
114            .map_err(|_| BuiltinActorError::MessageMappingError)?;
115
116        Ok(Self::encode(point))
117    }
118}
119
120impl Bls12_381OpsLowLevel {
121    fn msm_sw<T: SWCurveConfig>(
122        bases: Vec<u8>,
123        scalars: Vec<u8>,
124    ) -> Result<Vec<u8>, BuiltinActorError> {
125        let bases = Self::decode::<Vec<SWAffine<T>>>(bases)?;
126        let scalars = Self::decode::<Vec<<T as CurveConfig>::ScalarField>>(scalars)?;
127        let res = <SWProjective<T> as VariableBaseMSM>::msm(&bases, &scalars).map_err(|_| {
128            BuiltinActorError::Custom(LimitedStr::from_small_str("MSM SW: computation error"))
129        })?;
130
131        Ok(Self::encode_proj_sw(&res))
132    }
133
134    fn projective_mul_sw<T: SWCurveConfig>(
135        base: Vec<u8>,
136        scalar: Vec<u8>,
137    ) -> Result<Vec<u8>, BuiltinActorError> {
138        let base = Self::decode_proj_sw::<T>(base)?;
139        let scalar = Self::decode::<Vec<u64>>(scalar)?;
140        let res = <T as SWCurveConfig>::mul_projective(&base, &scalar);
141
142        Ok(Self::encode_proj_sw(&res))
143    }
144
145    fn encode<T: CanonicalSerialize>(val: T) -> Vec<u8> {
146        ArkScaleLocal::from(val).encode()
147    }
148
149    fn decode<T: CanonicalDeserialize>(buf: Vec<u8>) -> Result<T, BuiltinActorError> {
150        ArkScaleLocal::<T>::decode(&mut &buf[..])
151            .map(|v| v.0)
152            .map_err(|_| BuiltinActorError::DecodingError)
153    }
154
155    fn encode_proj_sw<T: SWCurveConfig>(val: &SWProjective<T>) -> Vec<u8> {
156        ArkScaleProjective::from(val).encode()
157    }
158
159    fn decode_proj_sw<T: SWCurveConfig>(
160        buf: Vec<u8>,
161    ) -> Result<SWProjective<T>, BuiltinActorError> {
162        ArkScaleProjective::decode(&mut &buf[..])
163            .map(|v| v.0)
164            .map_err(|_| BuiltinActorError::DecodingError)
165    }
166}